早上好,
我正在运行一段代码并且需要花费太长时间。目标是制定一个移动平均线"最近X天数。在这种情况下,前两天,3天,4天和5天的分数。它必须是最后一个日期Date
,用于唯一身份EID
。这是数据:
df:
EID Date Score
1111 5/25/2015 10
1111 5/29/2015 6
1111 6/17/2015 9
12345 5/27/2015 10
12345 1/1/2015 8
12345 1/7/2015 9
12345 1/9/2015 10
12345 1/10/2015 7
19611 1/13/2015 8
19611 1/21/2015 10
19611 1/23/2015 9
19611 1/24/2015 10
19611 1/30/2015 5
19611 2/5/2015 6
19611 2/11/2015 10
19611 2/12/2015 7
19611 2/14/2015 10
19611 2/15/2015 6
19611 2/18/2015 10
19611 2/19/2015 10
这就是我目前在6个数据帧上运行500,000多行
uniqueID <- unique(df$EID)
rowNr <- lapply(uniqueID,function(uniqueID){which(df$EID==uniqueID)})
lastDate <- lapply(rowNr,function(n){df$Date[rev(n)[1]]})
Avg <- lapply(rowNr,function(n){mean(df$Score[n])})
prev2 <- lapply(rowNr,function(n){mean(df$Score[head(tail(c(NA,n),3),2)])})
prev3 <- lapply(rowNr,function(n){mean(df$Score[head(tail(c(NA,n),4),3)])})
prev4 <- lapply(rowNr,function(n){mean(df$Score[head(tail(c(NA,n),5),4)])})
prev5 <- lapply(rowNr,function(n){mean(df$Score[head(tail(c(NA,n),6),5)])})
Scores <- data.frame(EID = uniqueID,
avg_score = unlist(Avg),
score2 = unlist(prev2),
score3 = unlist(prev3),
score4 = unlist(prev4),
score5 = unlist(prev5))
以下是结果
View(Scores)
EID avg_score score2 score3 score4 score5
1111 8.33 7.50 8.33 NA NA
12345 8.80 8.50 8.67 8.50 8.80
19611 8.42 10.00 8.67 9.00 8.60
任何想让它运行得更快的想法?我目前在6个数据帧上运行它,每个处理需要10-15分钟。 如何优化以更快地运行?
谢谢!
答案 0 :(得分:3)
这是一个data.table解决方案。
library(data.table)
n <- c(2,3,4,5)
result <- setDT(df)[,c(mean(Score),lapply(n,function(i){if(.N < i) as.numeric(NA) else mean(tail(Score,i))})),by=EID]
setnames(result,c("EID","avg_score",paste0("score",n)))
result
# EID avg_score score2 score3 score4 score5
# 1: 1111 8.333333 7.5 8.333333 NA NA
# 2: 12345 8.800000 8.5 8.666667 8.5 8.8
# 3: 19611 8.416667 10.0 8.666667 9.0 8.6
这会重现您的结果,但正如评论中所指出的,您的行不是所有EID
的日期顺序。如果这很重要,请使用:
setDT(df)[,Date:=as.Date(Date, format="%m/%d/%Y")]
setkey(df,EID,Date) # ensures that Dates are ascending within EID
n <- c(2,3,4,5)
result <- df[,c(mean(Score),lapply(n,function(i){if(.N < i) as.numeric(NA) else mean(tail(Score,i))})),by=EID]
setnames(result,c("EID","avg_score",paste0("score",n)))
result
# EID avg_score score2 score3 score4 score5
# 1: 1111 8.333333 7.5 8.333333 NA NA
# 2: 12345 8.800000 8.5 9.000000 9 8.8
# 3: 19611 8.416667 10.0 8.666667 9 8.6
如果您需要(2,3,4,5)以外的回滚平均值,请更改n
的定义。