2012-01-17 4 views
9

Io uso ddply di riassumere alcuni data.frame da diverse categorie, in questo modo:Come posso usare ddply con variabili variabili?

# with both group and size being factors/categorical 
split.df <- ddply(mydata,.(group,size),summarize, 
        sumGroupSize = sum(someValue)) 

Questo funziona senza problemi, ma spesso mi piace per calcolare i rapporti che implica che ho bisogno di dividere per totale del gruppo. Come posso calcolare tale totale all'interno della stessa chiamata ddply?

Diciamo che mi piacerebbe avere la quota di osservazioni nel gruppo A che sono in classe di dimensione 1. Ovviamente devo calcolare la somma di tutte le osservazioni nella classe di dimensione 1 prima. Certo, potrei farlo con due chiamate ddply, ma usare tutte le chiamate sarebbe più comodo. c'è un modo per farlo?

EDIT: Non intendevo chiedere eccessivamente specifico, ma mi rendo conto che stavo disturbando le persone qui. Quindi, ecco il mio problema specifico. In effetti, ho un esempio che funziona, ma non lo considero davvero elegante. Inoltre ha una lacuna che ho bisogno di superare: non funziona correttamente con apply.

library(plyr) 

# make the dataset more "realistic" 
mydata <- warpbreaks 
names(mydata) <- c("someValue","group","size") 
mydata$category <- c(1,2,3) 
mydata$categoryA <- c("A","A","X","X","Z","Z") 
# add some NA 
mydata$category[c(8,10,19)] <- NA 
mydata$categoryA[c(14,1,20)] <- NA 


# someValue is summarized ! 
# note we have a another, varying category hence we need the a parameter 
calcShares <- function(a, data) { 
# !is.na needs to be specific! 
tempres1 <- eval(substitute(ddply(data[!is.na(a),],.(group,size,a),summarize, 
       sumTest = sum(someValue,na.rm=T))), 

       envir=data, enclos=parent.frame()) 
tempres2 <- eval(substitute(ddply(data[!is.na(a),],.(group,size),summarize, 
       sumTestTotal = sum(someValue,na.rm=T))), 
       envir=data, enclos=parent.frame()) 

res <- merge(tempres1,tempres2,by=c("group","size")) 
res$share <- res$sumTest/res$sumTestTotal 
return(res) 

} 

test <- calcShares(category,mydata) 
test2 <- calcShares(categoryA,mydata) 
head(test) 
head(test2) 

Come puoi vedere, ho intenzione di farlo su diverse variabili categoriali. Nell'esempio ne ho solo due (categoria, categoria A) ma in realtà ne ho altri, quindi usare apply con la mia funzione sarebbe davvero bello, ma in qualche modo non funziona correttamente.

applytest <- head(apply(mydata[grep("^cat", 
      names(mydata),value=T)],2,calcShares,data=mydata)) 

.. restituisce un messaggio di avviso e un nome strano (newX [, i]) per la categoria var.

Quindi, come posso fare questo a) più elegantemente e b) risolvere il problema di applicazione?

+0

Nice Q. L'ho sempre fatto con ddply avvolto in un altro ddply come hai detto tu, quindi sono interessato a una soluzione anche a questo. 'Table' +' prop.table' + 'addmargins' funzionano per te, o hai bisogno della flessibilità aggiuntiva di ddply? –

+0

Non useresti la funzione 'count' per quello? La mia memoria è che si tratta solo di una ridenominazione di 'length' che era necessario usare con' ave' nella base R. –

+0

Hmm. bello, non sapevo di prop.table, ma potrei comunque sfruttare la flessibilità di ddply. –

risposta

3

Questo sembra semplice, quindi potrei mancare qualche aspetto della tua domanda.

Innanzitutto, definire una funzione che calcoli i valori desiderati all'interno di ciascun livello di group. Quindi, anziché utilizzare .(group, size) per suddividere il data.frame, utilizzare .(group) e applicare la funzione appena definita a ciascuno dei pezzi suddivisi.

library(plyr) 

# Create a dataset with the names in your example 
mydata <- warpbreaks 
names(mydata) <- c("someValue", "group", "size") 

# A function that calculates the proportional contribution of each size class 
# to the sum of someValue within a level of group 
getProps <- function(df) { 
    with(df, ave(someValue, size, FUN=sum)/sum(someValue)) 
} 

# The call to ddply() 
res <- ddply(mydata, .(group), 
      .fun = function(X) transform(X, PROPS=getProps(X))) 

head(res, 12) 
# someValue group size  PROPS 
# 1   26  A L 0.4785203 
# 2   30  A L 0.4785203 
# 3   54  A L 0.4785203 
# 4   25  A L 0.4785203 
# 5   70  A L 0.4785203 
# 6   52  A L 0.4785203 
# 7   51  A L 0.4785203 
# 8   26  A L 0.4785203 
# 9   67  A L 0.4785203 
# 10  18  A M 0.2577566 
# 11  21  A M 0.2577566 
# 12  29  A M 0.2577566 
+0

+1 per portare alcuni pensieri nuovi (con/ave/transform) al tavolo. Mi sono reso conto che ero un po 'impreciso e ho pubblicato un esempio riproducibile più specifico. Ciò che manca alla tua soluzione è il sommario (cioè l'aggregazione). Ma forse puoi aggiungerlo in qualche modo alla tua soluzione. Non mi concentro solo su ddply :) –

+0

Mi piace anche questo, ma non so se è più semplice di fare semplicemente 2x ddply sin dall'inizio. –