لكل مستوى من القيم الإجمالية للعامل على جميع المستويات باستثناء المستوى الحالي
-
11-12-2019 - |
سؤال
بالنسبة لكل مستوى من العوامل، أحتاج إلى استخراج القيم المجمعة على جميع المجموعات الفرعية من data.frame باستثناء المجموعة الحالية.على سبيل المثال، هناك عدة أشخاص يقومون بمهمة وقت رد الفعل خلال عدة أيام، وأحتاج إلى حساب متوسط وقت رد الفعل لجميع المواد وجميع الأيام، ولكن لا يشمل الشخص الذي تم حساب المتوسط له.حاليا أفعل ذلك مثل هذا:
library(lme4)
ddply(sleepstudy, .(Subject, Days), summarise,
avg_rt = mean(sleepstudy[sleepstudy$Subject != Subject &
sleepstudy$Days == Days,"Reaction"]), .progress="text")
إنه يعمل بشكل جيد مع مجموعات البيانات الصغيرة، ولكن بالنسبة للمجموعات الكبيرة يمكن أن يكون بطيئًا جدًا.هل هناك طريقة للقيام بذلك بشكل أسرع؟
المحلول
#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
بالنسبة لمجموعات البيانات الكبيرة حقًا، يجب أن يكون اكتساب السرعة أكثر وضوحًا.لم أتمكن من المقارنة مع مجموعات البيانات الأكبر منذ ذلك الحين ddply
بطيء جدًا.
نصائح أخرى
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