慢慢转换数据帧处理 - R.

时间:2015-10-08 15:23:18

标签: r performance optimization

早上好,

我正在运行一段代码并且需要花费太长时间。目标是制定一个移动平均线"最近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分钟。 如何优化以更快地运行?

谢谢!

1 个答案:

答案 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的定义。