Pour chaque niveau de valeurs globales de facteur sur tous les niveaux, à l'exception de l'actuel
-
11-12-2019 - |
Question
Pour chaque niveau de facteur, j'ai besoin d'extraire des valeurs agrégées sur tous les sous-ensembles de données. Sauf le présent.Par exemple, plusieurs sujets effectuent une tâche de temps de réaction pendant plusieurs jours et j'ai besoin de calculer du temps de réaction moyen pour tous les sujets et tous les jours, mais sans inclure le sujet pour lequel la moyenne est calculée.Actuellement, je le fais comme ceci:
library(lme4)
ddply(sleepstudy, .(Subject, Days), summarise,
avg_rt = mean(sleepstudy[sleepstudy$Subject != Subject &
sleepstudy$Days == Days,"Reaction"]), .progress="text")
Cela fonctionne bien pour les petits ensembles de données, mais pour les grands, cela peut être très lent.Y a-t-il un moyen de le faire plus vite?
La solution
#create big dataset
n <- 1e4
set.seed(1)
sleepstudy <- data.frame(Reaction=rnorm(n),Subject=1:4,Days=sort(rep((1:(n/4)),4)))
library(plyr)
system.time(
res <- ddply(sleepstudy, .(Subject, Days), summarise,
avg_rt = mean(sleepstudy[sleepstudy$Subject != Subject &
sleepstudy$Days == Days,"Reaction"]))
)
#User System elapsed
#6.532 0.013 6.556
#use data.table for big datasets
library(data.table)
dt<- as.data.table(sleepstudy)
system.time(
{dt[,avg_rt:=mean(Reaction),by=Days];
dt[,n:=.N,by=Days];
dt[,avg_rt:=(avg_rt*n-Reaction)/(n-1)]}
)
#User System elapsed
#0.005 0.001 0.005
#test if results are equal
dt2 <- as.data.table(res)
setkey(dt2,Subject,Days)
setkey(dt,Subject,Days)
all.equal(dt[,avg_rt],dt2[,avg_rt])
#[1] TRUE
Pour de très grands ensembles de données, le gain de vitesse devrait être plus prononcé.Je ne pouvais tout simplement pas comparer avec des jeux de données plus importants puisque ddply
est si lent.
Autres conseils
Maybe it's faster with lapply
and aggregate
:
do.call("rbind", (lapply(unique(sleepstudy$Subject),
function(x)
cbind(Subject = x,
aggregate(Reaction ~ Days,
subset(sleepstudy, Subject != x),
mean)))))
Update:
I compared both commands with system.time
and it appears the original is slower.
library(lme4)
library(plyr)
system.time(
ddply(sleepstudy, .(Subject, Days), summarise,
avg_rt = mean(sleepstudy[sleepstudy$Subject != Subject &
sleepstudy$Days == Days,"Reaction"]))
)
# user system elapsed
# 0.17 0.00 0.22
system.time(
do.call("rbind", (lapply(unique(sleepstudy$Subject),
function(x)
cbind(Subject = x,
aggregate(Reaction ~ Days,
subset(sleepstudy, Subject != x),
mean)))))
)
# user system elapsed
# 0.12 0.00 0.12