2009-08-11 20 views
8

Qui faccio una nuova colonna per indicare se myData è al di sopra o al di sotto la sua medianaCome si fa la divisione mediana all'interno dei livelli di fattore in 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 

funziona bene. Ora voglio fare la stessa cosa, ma calcolare le divisioni mediane all'interno di ciascun livello di myFactor.

mi è venuta in mente questo:

#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 quello che voglio. Classifica in modo corretto ogni elemento dei fattori A, B e C. Tuttavia mi piacerebbe creare una nuova colonna, myDataFrame $ FactorLevelMedianSplit, che mostra la divisione mediana appena calcolata.

Come si converte l'output del comando "by" in un'utile colonna di dati frame?

Penso che forse il "di" comando non è R-come modo per fare questo ...

Aggiornamento:

Con l'esempio di Thierry di come utilizzare il fattore() abilmente, e su scoprendo la funzione "ave" nel libro di Spector, ho trovato questa soluzione, che non richiede pacchetti aggiuntivi.

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 soluzione packageless per questo è bello - grazie! – Amyunimus

risposta

3

Ecco una soluzione che utilizza il pacchetto 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

Questo ha funzionato alla grande. Vedi anche l'aggiornamento al post per un modo senza pack. –

1

Ecco un modo hack-ish. Hadley può venire con qualcosa di più elegante:

Per iniziare, abbiamo semplice concatenare i by uscita:

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 

e quello che conta che si ottengono i livelli di fattore 1 e 2 qui che possiamo utilizzare per ri-index un nuovo fattore con quei livelli:

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 

quale possiamo quindi assegnare in data.frame si voleva modificare:

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

Aggiornamento: Non importa, dovremmo reindicizzare myDataFrame per essere ordinati A A ... A B ... B C ... C prima di aggiungere la nuova colonna. Lasciato come esercizio ...