R-Paket zum Kombinieren von Faktorstufen für die Datenerfassung?

10

Sie fragen sich, ob jemand in R auf ein Paket / eine Funktion gestoßen ist, die Ebenen eines Faktors kombiniert, dessen Anteil an allen Ebenen in einem Faktor unter einem bestimmten Schwellenwert liegt? Insbesondere besteht einer der ersten Schritte bei der Datenaufbereitung darin, spärliche Ebenen von Faktoren zusammenzufassen (z. B. zu einer Ebene namens "Andere"), die nicht mindestens 2% der Gesamtmenge ausmachen. Dies geschieht unbeaufsichtigt und dann, wenn das Ziel darin besteht, bestimmte Aktivitäten im Marketing zu modellieren (keine Betrugserkennung, bei der diese sehr kleinen Vorkommnisse äußerst wichtig sein können). Ich suche nach einer Funktion, die Ebenen zusammenbricht, bis ein bestimmter Schwellenwert erreicht ist.

AKTUALISIEREN:

Dank dieser großartigen Vorschläge habe ich ziemlich einfach eine Funktion geschrieben. Mir war jedoch klar, dass es möglich war, Ebenen mit einem Anteil <dem Minimum zu kollabieren und diesen neu codierten Wert dennoch <das Minimum zu haben, was die Hinzufügung des niedrigsten Niveaus mit Anteil> dem Minimum erforderlich machte. Kann wahrscheinlich effizienter sein, aber es scheint zu funktionieren. Die nächste Verbesserung wäre, herauszufinden, wie die "Regeln" für die Anwendung der Kollapslogik auf neue Daten (einen Validierungssatz oder zukünftige Daten) erfasst werden können.

collapseFactors<- function(tableName,minPercent=5,fillIn ="RECODED" )
{
    for (i in 1:ncol(tableName))
        {   

            if(is.factor(tableName[,i]) == TRUE) #process just factors
            {


                sortedTable<-sort(prop.table(table(tableName[,i])))
                numberToCollapse<-length(sortedTable[sortedTable<(minPercent/100)])

                if (sum(sortedTable[1:numberToCollapse])<(minPercent/100))
                    {
                        numberToCollapse=numberToCollapse+1 #add next level if < minPercent
                    }

                if(numberToCollapse>1) #if not >1 then nothing to collapse
                {
                    lf <- names(sortedTable[1:numberToCollapse])
                    levels(tableName[,i])[levels(tableName[,i]) %in% lf] <- fillIn
                }
            }#end if a factor


        }#end for loop

    return(tableName)

}#end function
B_Miner
quelle
Für einen anderen Ansatz: stats.stackexchange.com/questions/227125/…
kjetil b halvorsen

Antworten:

11

Es scheint nur eine Frage des "Neuentwickelns" des Faktors zu sein; Es ist nicht erforderlich, Teilsummen zu berechnen oder eine Kopie des ursprünglichen Vektors zu erstellen. Z.B,

set.seed(101)
a <- factor(LETTERS[sample(5, 150, replace=TRUE, 
                           prob=c(.1, .15, rep(.75/3,3)))])
p <- 1/5
lf <- names(which(prop.table(table(a)) < p))
levels(a)[levels(a) %in% lf] <- "Other"

Hier sind die ursprünglichen Faktorstufen wie folgt verteilt:

 A  B  C  D  E 
18 23 35 36 38 

und dann wird es

Other     C     D     E 
   41    35    36    38 

Es kann bequem in eine Funktion eingewickelt werden. combine_factor()Das Umformungspaket enthält eine Funktion , daher könnte sie auch nützlich sein.

Wenn Sie an Data Mining interessiert zu sein scheinen, sollten Sie sich auch das Caret- Paket ansehen . Es verfügt über viele nützliche Funktionen für die Datenvorverarbeitung, einschließlich solcher Funktionen nearZeroVar(), mit denen Prädiktoren mit einer sehr unausgewogenen Verteilung der beobachteten Werte gekennzeichnet werden können (siehe Vignette, Beispieldaten, Vorverarbeitungsfunktionen, Visualisierungen und andere Funktionen , S. 5) von Nutzen).

chl
quelle
@ CHI Danke. Ich habe das Caret-Paket studiert und es verwendet, um Metaparameter abzustimmen. sehr hilfreich!.
B_Miner
@chl +1, schön. Ich habe meine Funktion nur geschrieben, weil Code a [Ebenen (a)% in% lf] <- "Andere" nicht funktioniert, daher habe ich angenommen, dass die Änderung der Faktorebene eine komplizierte Angelegenheit ist. Wie immer stellte sich heraus, dass R nicht kompliziert ist, ich bin :)
mpiktas
@mpiktas Thx. Sie können auf Vektorebene mit z a[as.character(a) %in% lf] <- lf[1]; a <- factor(droplevels(a), labels=c("Other",LETTERS[3:5])).
Chl
+1. a [Ebenen (a)% in% lf] <- "Andere" spart sicher eine Menge Codezeilen. Clever und effizient!
Christopher Aden
Beachten Sie jedoch, dass a [a == "a"] <- "Other" nicht funktioniert, was für mich ganz natürlich ist, anzunehmen, dass dies der Fall sein sollte. Zumal a [a == "a"] vollkommen gültig ist.
mpiktas
5

Das einzige Problem mit der Antwort von Christopher ist, dass die ursprüngliche Reihenfolge des Faktors verwechselt wird. Hier ist mein Fix:

 Merge.factors <- function(x, p) {
     t <- table(x)
     levt <- cbind(names(t), names(t)) 
     levt[t/sum(t)<p, 2] <- "Other"
     change.levels(x, levt)
 }

Wo change.levelsist die folgende Funktion. Ich habe es vor einiger Zeit geschrieben, daher vermute ich, dass es bessere Möglichkeiten gibt, das zu erreichen, was es tut.

 change.levels <- function(f, levt) {
     ##Change the the names of the factor f levels from
     ##substitution table levt.
     ## In the first column there are the original levels, in
     ## the second column -- the substitutes
     lv <- levels(f)
     if(sum(sort(lv) != sort(levt[, 1]))>0)
     stop ("The names from substitution table does not match given level names")
     res <- rep(NA, length(f))

     for(i in lv) {
          res[f==i] <- as.character(levt[levt[, 1]==i, 2])
     }
     factor(res)
}
mpiktas
quelle
4

Ich habe eine schnelle Funktion geschrieben, die dieses Ziel erreicht. Ich bin ein unerfahrener R-Benutzer, daher kann es bei großen Tabellen langsam sein.

Merge.factors <- function(x, p) { 
    #Combines factor levels in x that are less than a specified proportion, p.
    t <- table(x)
    y <- subset(t, prop.table(t) < p)
    z <- subset(t, prop.table(t) >= p)
    other <- rep("Other", sum(y))
    new.table <- c(z, table(other))
    new.x <- as.factor(rep(names(new.table), new.table))
    return(new.x)
}

Als Beispiel dafür in Aktion:

> a <- rep("a", 100)
> b <- rep("b", 1000)
> c <- rep("c", 1000)
> d <- rep("d", 1000)
> e <- rep("e", 400)
> f <- rep("f", 100)
> x <- factor(c(a, b, c, d, e, f))
> summary(x)
   a    b    c    d    e    f 
 100 1000 1000 1000  400  100 
> prop.table(table(x))
x
         a          b          c          d          e          f 
0.02777778 0.27777778 0.27777778 0.27777778 0.11111111 0.02777778 
> 
> w <- Merge.factors(x, .05)
> summary(w)
    b     c     d     e Other 
 1000  1000  1000   400   200 
> class(w)
[1] "factor"
Christopher Aden
quelle
Danke für die Beobachtung, John. Ich habe es ein wenig geändert, um es zu einem Faktor zu machen. Ich habe jedoch nur den ursprünglichen Vektor aus der Tabelle neu erstellt. Wenn es also eine Möglichkeit gibt, diesen Schritt zu überspringen, ist dies schneller.
Christopher Aden
Vielen Dank an alle, die geantwortet haben. Mein R ist schwach, aber die Fähigkeit, dies mit so wenigen Codezeilen zu tun, ist ein Beweis dafür, wie leistungsfähig es ist und bringt mich dazu, lernen zu wollen.
B_Miner