【发布时间】:2012-05-22 13:43:07
【问题描述】:
让我们获取以下数据:
dt <- data.table(TICKER=c(rep("ABC",10),"DEF"),
PERIOD=c(rep(as.Date("2010-12-31"),10),as.Date("2011-12-31")),
DATE=as.Date(c("2010-01-05","2010-01-07","2010-01-08","2010-01-09","2010-01-10","2010-01-11","2010-01-13","2010-04-01","2010-04-02","2010-08-03","2011-02-05")),
ID=c(1,2,1,3,1,2,1,1,2,2,1),VALUE=c(1.5,1.3,1.4,1.6,1.4,1.2,1.5,1.7,1.8,1.7,2.3))
setkey(dt,TICKER,PERIOD,ID,DATE)
现在对于每个代码/周期组合,我需要在新列中添加以下内容:
-
PRIORAVG:每个 ID 的最新 VALUE 的平均值,不包括当前 ID,前提是它不超过 180 天。 -
PREV:来自同一个 ID 的前一个值。
结果应该是这样的:
TICKER PERIOD DATE ID VALUE PRIORAVG PREV
[1,] ABC 2010-12-31 2010-01-05 1 1.5 NA NA
[2,] ABC 2010-12-31 2010-01-08 1 1.4 1.30 1.5
[3,] ABC 2010-12-31 2010-01-10 1 1.4 1.45 1.4
[4,] ABC 2010-12-31 2010-01-13 1 1.5 1.40 1.4
[5,] ABC 2010-12-31 2010-04-01 1 1.7 1.40 1.5
[6,] ABC 2010-12-31 2010-01-07 2 1.3 1.50 NA
[7,] ABC 2010-12-31 2010-01-11 2 1.2 1.50 1.3
[8,] ABC 2010-12-31 2010-04-02 2 1.8 1.65 1.2
[9,] ABC 2010-12-31 2010-08-03 2 1.7 1.70 1.8
[10,] ABC 2010-12-31 2010-01-09 3 1.6 1.35 NA
[11,] DEF 2011-12-31 2011-02-05 1 2.3 NA NA
注意第 9 行的 PRIORAVG 等于 1.7(这等于第 5 行的 VALUE,这是过去 180 天内另一个 ID 的唯一先前观察)
我发现了data.table 包,但我似乎无法完全理解:= 功能。当我保持简单时,它似乎有效。获取每个ID的先前值(我基于this question的解决方案):
dt[,PREV:=dt[J(TICKER,PERIOD,ID,DATE-1),roll=TRUE,mult="last"][,VALUE]]
这很好用,只需 0.13 秒即可对我的数据集执行此操作,其中包含约 250k 行;我的矢量扫描函数得到了相同的结果,但速度慢了大约 30,000 倍。
好的,所以我有我的第一个要求。让我们来看看第二个更复杂的需求。目前对我来说,目前禁食的方法是使用几个向量扫描并通过plyr 函数adply 抛出函数来获得每一行的结果。
calc <- function(df,ticker,period,id,date) {
df <- df[df$TICKER == ticker & df$PERIOD == period
& df$ID != id & df$DATE < date & df$DATE > date-180, ]
df <- df[order(df$DATE),]
mean(df[!duplicated(df$ID, fromLast = TRUE),"VALUE"])
}
df <- data.frame(dt)
adply(df,1,function(x) calc(df,x$TICKER,x$PERIOD,x$ID,x$DATE))
我为data.frame 编写了函数,但它似乎不适用于data.table。对于 5000 行的子集,这大约需要 44 秒,但我的数据包含超过 100 万行。我想知道是否可以通过使用:= 来提高效率。
dt[J("ABC"),last(VALUE),by=ID][,mean(V1)]
这可以为 ABC 的每个 ID 选择最新 VALUE 的平均值。
dt[,PRIORAVG:=dt[J(TICKER,PERIOD),last(VALUE),by=ID][,mean(V1)]]
但是,这并没有按预期工作,因为它取所有代码/周期的所有最后 VALUE 的平均值,而不仅仅是当前代码/周期。所以最终所有行都获得相同的平均值。我做错了什么还是这是:=的限制?
【问题讨论】:
-
提示:加入过去 180 天流行观察的继承范围(使用
i.前缀:[,j=list(...,age=PERIOD-i.PERIOD,...),][age<180]和mult="last",而不是last(),也许。 -
有问题的数据面板看起来与上面的代码提取不同。它似乎缺少
)。 -
添加了显示 180 天要求的预期结果的数据
标签: r data.table