modo più veloce per creare una variabile che aggrega una colonna per id

C’è un modo più veloce per farlo? Immagino che questo non sia necessario lento e che un compito come questo può essere realizzato con le funzioni di base.

df <- ddply(df, "id", function(x) cbind(x, perc.total = sum(x$cand.perc))) 

Sono abbastanza nuovo per R. Ho guardato by() , aggregate() e tapply() , ma non ho potuto farli funzionare affatto o nel modo in cui volevo. Piuttosto che restituire un vettore più breve, voglio albind la sum al dataframe originale. Qual è il modo migliore per farlo?

Modifica: ecco un confronto di velocità delle risposte applicate ai miei dati.

 > # My original solution > system.time( ddply(df, "id", function(x) cbind(x, perc.total = sum(x$cand.perc))) ) user system elapsed 14.405 0.000 14.479 > # Paul Hiemstra > system.time( ddply(df, "id", transform, perc.total = sum(cand.perc)) ) user system elapsed 15.973 0.000 15.992 > # Richie Cotton > system.time( with(df, tapply(df$cand.perc, df$id, sum))[df$id] ) user system elapsed 0.048 0.000 0.048 > # John > system.time( with(df, ave(cand.perc, id, FUN = sum)) ) user system elapsed 0.032 0.000 0.030 > # Christoph_J > system.time( df[ , list(perc.total = sum(cand.perc)), by="id"][df]) user system elapsed 0.028 0.000 0.028 

Per qualsiasi tipo di aggregazione in cui si desidera che il vettore risultante abbia la stessa lunghezza del vettore di input con i replicati raggruppati nel vettore di raggruppamento, è ciò che si desidera.

 df$perc.total <- ave(df$cand.perc, df$id, FUN = sum) 

Dato che sei abbastanza nuovo per R e la velocità è apparentemente un problema per te, ti consiglio il pacchetto data.table , che è veramente veloce. Un modo per risolvere il problema in una riga è il seguente:

 library(data.table) DT <- data.table(ID = rep(c(1:3), each=3), cand.perc = 1:9, key="ID") DT <- DT[ , perc.total := sum(cand.perc), by = ID] DT ID Perc.total cand.perc [1,] 1 6 1 [2,] 1 6 2 [3,] 1 6 3 [4,] 2 15 4 [5,] 2 15 5 [6,] 2 15 6 [7,] 3 24 7 [8,] 3 24 8 [9,] 3 24 9 

Disclaimer: non sono un esperto di data.table (ancora ;-), quindi potrebbero esserci modi più veloci per farlo. Consulta il sito del pacchetto per iniziare se sei interessato a utilizzare il pacchetto: http://datatable.r-forge.r-project.org/

Usa tapply per ottenere le statistiche di gruppo, quindi aggiungile di nuovo nel set di dati in seguito.

Esempio riproducibile:

 means_by_wool <- with(warpbreaks, tapply(breaks, wool, mean)) warpbreaks$means.by.wool <- means_by_wool[warpbreaks$wool] 

Soluzione non testata per il tuo scenario:

 sum_by_id <- with(df, tapply(cand.perc, id, sum)) df$perc.total <- sum_by_id[df$id] 

ilprincipe se nessuna delle risposte precedenti soddisfa le tue esigenze puoi provare a trasporre i tuoi dati

 dft=t(df) 

quindi utilizzare aggregate

 dfta=aggregate(dft,by=list(rownames(dft)),FUN=sum) 

dopo hai indietro i tuoi nomi

 rownames(dfta)=dfta[,1] dfta=dfta[,2:ncol(dfta)] 

Riporta all’orientamento originale

 df2=t(dfta) 

e si legano ai dati originali

 newdf=cbind(df,df2) 

Perché stai usando cbind (x, …) l’output di ddply verrà aggiunto automaticamente. Questo dovrebbe funzionare:

 ddply(df, "id", transform, perc.total = sum(cand.perc)) 

sbarazzarsi del superfluo dovrebbe accelerare le cose.

Puoi anche caricare il tuo backend foreach preferito e provare l’argomento .parallel = TRUE per ddply.