2009-08-11 17 views
8

Aquí hago una nueva columna para indicar si myData está por encima o por debajo de su media fina¿Cómo hacer divisiones medianas dentro de los niveles de los factores en R?

### MedianSplits based on Whole Data 
#create some test data 
myDataFrame=data.frame(myData=runif(15),myFactor=rep(c("A","B","C"),5)) 

#create column showing median split 
myBreaks= quantile(myDataFrame$myData,c(0,.5,1)) 
myDataFrame$MedianSplitWholeData = cut(
    myDataFrame$myData, 
    breaks=myBreaks, 
    include.lowest=TRUE, 
    labels=c("Below","Above")) 

#Check if it's correct 
myDataFrame$AboveWholeMedian = myDataFrame$myData > median(myDataFrame$myData) 
myDataFrame 

Works. Ahora quiero hacer lo mismo, pero calculo las divisiones medianas dentro de cada nivel de myFactor.

Yo he llegado con esto:

#Median splits within factor levels 
byOutput=by(myDataFrame$myData,myDataFrame$myFactor, function (x) { 
    myBreaks= quantile(x,c(0,.5,1)) 
    MedianSplitByGroup=cut(x, 
     breaks=myBreaks, 
     include.lowest=TRUE, 
     labels=c("Below","Above")) 
    MedianSplitByGroup 
    }) 

byOutput contiene lo que quiero. Clasifica cada elemento de los factores A, B y C correctamente. Sin embargo, me gustaría crear una nueva columna, myDataFrame $ FactorLevelMedianSplit, que muestre la división mediana recientemente calculada.

¿Cómo se convierte la salida del comando "por" en una útil columna de marco de datos?

creo que quizás el "por" comando no es R-como forma de hacer esto ...

actualización:

Con ejemplo de cómo utilizar los factores (Thierry) inteligentemente, y sobre descubriendo la función "ave" en el libro de Spector, encontré esta solución, que no requiere paquetes adicionales.

myDataFrame$MediansByFactor=ave(
    myDataFrame$myData, 
    myDataFrame$myFactor, 
    FUN=median) 

myDataFrame$FactorLevelMedianSplit = factor(
    myDataFrame$myData>myDataFrame$MediansByFactor, 
    levels = c(TRUE, FALSE), 
    labels = c("Above", "Below")) 
+0

La solución sin paquete es hermosa, ¡gracias! – Amyunimus

Respuesta

3

Aquí hay una solución usando el paquete plyr.

myDataFrame <- data.frame(myData=runif(15),myFactor=rep(c("A","B","C"),5)) 
library(plyr) 
ddply(myDataFrame, "myFactor", function(x){ 
    x$Median <- median(x$myData) 
    x$FactorLevelMedianSplit <- factor(x$myData <= x$Median, levels = c(TRUE, FALSE), labels = c("Below", "Above")) 
    x 
}) 
+0

Esto funcionó muy bien. Ver también la actualización de la publicación de una manera sin paquete. –

1

Aquí hay una forma de hack-ish. Hadley puede venir con algo más elegante:

Para empezar, sencilla concatenamos la by de salida:

R> do.call(c,byOutput) 
A1 A2 A3 A4 A5 B1 B2 B3 B4 B5 C1 C2 C3 C4 C5 
1 2 2 1 1 1 1 2 1 2 1 2 1 1 2 

y lo que importa es que se obtienen los niveles de los factores 1 y 2 aquí, que podemos utilizar para volver a indexar un nuevo factor con los niveles:

R> c("Below","Above")[do.call(c,byOutput)] 
[1] "Below" "Above" "Above" "Below" "Below" "Below" "Below" "Above" 
[8] "Below" "Above" "Below" "Above" "Below" "Below" "Above" 
R> as.factor(c("Below","Above")[do.call(c,byOutput)]) 
[1] Below Above Above Below Below Below Below Above Below Above 
[11] Below Above Below Below Above 
Levels: Above Below 

que podremos asignar a la data.frame que quería modificar:

R> myDataFrame$FactorLevelMedianSplit <- 
     as.factor(c("Below","Above")[do.call(c,byOutput)]) 

Actualización: No importa, tendríamos que reindexar myDataFrame para ordenar A A ... A B ... B C ... C también antes de agregar la nueva columna. Se dejó como un ejercicio ...

Cuestiones relacionadas