Como fazer splits medianos dentro de níveis de fator em R?
Pergunta
Aqui eu faço uma nova coluna para indicar se myData está acima ou abaixo de sua média
### 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
funciona bem. Agora eu quero fazer a mesma coisa, mas computar os splits medianos dentro de cada nível de myFactor.
Eu vim acima com este:
#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 contém o que eu quero. É categoriza cada elemento de factores A, B, e C correctamente. No entanto, eu gostaria de criar uma nova coluna, myDataFrame $ FactorLevelMedianSplit, que mostra a divisão mediana recém-calculado.
Como você converter a saída do "por" comando em uma coluna-frame dados úteis?
Eu acho que talvez o "por" comando não é R-like maneira de fazer isso ...
Atualizar :
Com exemplo de como usar o factor () inteligentemente, e ao descobrir a função de "ave" no livro de Spector de Thierry, eu encontrei esta solução, que não necessita de pacotes adicionais.
myDataFrame$MediansByFactor=ave(
myDataFrame$myData,
myDataFrame$myFactor,
FUN=median)
myDataFrame$FactorLevelMedianSplit = factor(
myDataFrame$myData>myDataFrame$MediansByFactor,
levels = c(TRUE, FALSE),
labels = c("Above", "Below"))
Solução
Aqui está uma solução usando o pacote 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
})
Outras dicas
Aqui está uma maneira Hack-ish. Hadley pode vir com algo mais elegante:
Para começar, nós simples concatenar a saída 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
e que importa que nós temos os níveis de fator 1 e 2 aqui que podemos usar para re-indexar um novo fator com esses níveis:
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 pode então atribuir no data.frame
você queria modificar:
R> myDataFrame$FactorLevelMedianSplit <-
as.factor(c("Below","Above")[do.call(c,byOutput)])
Atualizar : Nunca mente, tínhamos necessidade de reindexar myDataFrame a ser classificado A A ... A B ... B C ... C, bem antes de adicionar a nova coluna. Deixado como um exercício ...