2009-08-11 9 views
8

Ici je fais une nouvelle colonne pour indiquer si myData est au-dessus ou en dessous de sa médianeComment faire des divisions médianes dans les niveaux de facteur dans 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 

fonctionne très bien. Maintenant, je veux faire la même chose, mais calculer les divisions médianes dans chaque niveau de myFactor.

Je suis venu avec ceci:

#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 contient ce que je veux. Il catégorise correctement chaque élément des facteurs A, B et C. Cependant, j'aimerais créer une nouvelle colonne, myDataFrame $ FactorLevelMedianSplit, qui affiche la division médiane nouvellement calculée. Comment convertir la sortie de la commande "by" en une colonne de trame de données utile?

Je pense que peut-être le « par » commande n'est pas R comme façon de le faire ...

Mise à jour:

Avec Thierry de l'exemple de la façon d'utiliser le facteur() intelligemment, et sur En découvrant la fonction "ave" dans le livre de Spector, j'ai trouvé cette solution, qui ne nécessite aucun paquet supplémentaire.

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 solution sans emballage est belle - merci! – Amyunimus

Répondre

3

Voici une solution en utilisant le paquet de 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

Cela a bien fonctionné. Voir aussi la mise à jour de la poste pour un moyen sans emballage. –

1

Voici une manière hack-ish. Hadley peut venir avec quelque chose de plus élégant:

Pour commencer, nous simplement concaténer la sortie by:

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 

et ce qui importe que nous obtenons les niveaux de facteur 1 et 2 ici que nous pouvons utiliser pour réindexer un nouveau facteur avec ces niveaux:

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 nous pouvons attribuer dans le data.frame que vous vouliez modifier:

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

Mise à jour: Peu importe, nous aurions besoin de réindexer myDataFrame à trier A A ... A B ... B C ... C avant d'ajouter la nouvelle colonne. Gauche comme un exercice ...

Questions connexes