包含数据的表(它是一个data.table对象),如下所示:
date stock_id logret
1: 2011-01-01 1 0.001
2: 2011-01-02 1 0.003
3: 2011-01-03 1 0.005
4: 2011-01-04 1 0.007
5: 2011-01-05 1 0.009
6: 2011-01-06 1 0.011
7: 2011-01-01 2 0.013
8: 2011-01-02 2 0.015
9: 2011-01-03 2 0.017
10: 2011-01-04 2 0.019
11: 2011-01-05 2 0.021
12: 2011-01-06 2 0.023
13: 2011-01-01 3 0.025
14: 2011-01-02 3 0.027
15: 2011-01-03 3 0.029
16: 2011-01-04 3 0.031
17: 2011-01-05 3 0.033
18: 2011-01-06 3 0.035
以上内容可以创建为:
DT = data.table(
date=rep(as.Date('2011-01-01')+0:5,3) ,
stock_id=c(1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3),
logret=seq(0.001, by=0.002, len=18));
setkeyv(DT,c('stock_id','date'))
当然,真实的桌子更大,有更多的stock_ids和日期。目的是重新整形这个数据表,以便我可以运行所有stockid log_returns及其对应的log_returns的回归,滞后为1天(或者在周末的情况下交易前一天)。
最终结果如下:
date stock_id logret lagret
1: 2011-01-01 1 0.001 NA
2: 2011-01-02 1 0.003 0.001
3: 2011-01-03 1 0.005 0.003
....
16: 2011-01-04 3 0.031 0.029
17: 2011-01-05 3 0.033 0.031
18: 2011-01-06 3 0.035 0.033
我发现这个数据结构非常难以构建而不会混淆我的stockid。
答案 0 :(得分:21)
由于Alex的评论,还有一些额外的注释。你很难理解这里发生的事情是很多事情都是在一条线上完成的。因此,打破局面总是一个好主意。
我们真正想要的是什么?我们想要一个新列lagret
,并在data.table中添加新列的语法如下:
DT[, lagret := xxx]
其中xxx
必须填写列lagret
中您想要的内容。因此,如果我们只想要一个给我们行的新列,我们可以调用
DT[, lagret := seq(from=1, to=nrow(DT))]
在这里,我们实际上想要logret
的滞后值,但我们必须考虑到这里有很多股票。这就是我们进行自我加入的原因,即我们通过列DT
和stock_id
加入data.table date
,但由于我们想要每个股票的先前价值,我们使用date-1
。请注意,我们必须先设置密钥才能进行此类连接:
setkeyv(DT,c('stock_id','date'))
DT[list(stock_id,date-1)]
stock_id date logret
1: 1 2010-12-31 NA
2: 1 2011-01-01 0.001
3: 1 2011-01-02 0.003
4: 1 2011-01-03 0.005
5: 1 2011-01-04 0.007
6: 1 2011-01-05 0.009
...
如您所见,我们现在拥有我们想要的东西。 logret
现在滞后一个时期。但我们实际上希望在lagret
中的新列DT
中,所以我们只需通过调用[[3L]]来获取该列(这意味着没有其他任何内容,然后让我获得第三列)并将此命名为专栏lagret
:
DT[,lagret:=DT[list(stock_id,date-1),logret][[3L]]]
date stock_id logret lagret
1: 2011-01-01 1 0.001 NA
2: 2011-01-02 1 0.003 0.001
3: 2011-01-03 1 0.005 0.003
4: 2011-01-04 1 0.007 0.005
5: 2011-01-05 1 0.009 0.007
...
这已经是正确的解决方案。在这个简单的例子中,我们不需要roll=TRUE
,因为日期中没有空白。但是,在一个更现实的例子中(如上所述,例如当我们有周末时),可能存在差距。所以,让我们通过在DT
中删除第一个股票的两天来制作这样一个现实的例子:
DT <- DT[-c(4, 5)]
setkeyv(DT,c('stock_id','date'))
DT[,lagret:=DT[list(stock_id,date-1),logret][[3L]]]
date stock_id logret lagret
1: 2011-01-01 1 0.001 NA
2: 2011-01-02 1 0.003 0.001
3: 2011-01-03 1 0.005 0.003
4: 2011-01-06 1 0.011 NA
5: 2011-01-01 2 0.013 NA
...
正如您所看到的,问题是我们现在没有1月6日的价值。这就是我们使用roll=TRUE
:
DT[,lagret:=DT[list(stock_id,date-1),logret,roll=TRUE][[3L]]]
date stock_id logret lagret
1: 2011-01-01 1 0.001 NA
2: 2011-01-02 1 0.003 0.001
3: 2011-01-03 1 0.005 0.003
4: 2011-01-06 1 0.011 0.005
5: 2011-01-01 2 0.013 NA
...
只需查看有关roll=TRUE
如何正常工作的文档。简而言之:如果找不到之前的值(这里是1月5日的logret
),它只需要最后一个(从1月3日开始)。
答案 1 :(得分:4)
在data.table的当前开发版本中,v1.9.5,shift()
已实现#965,目前有两种类型type = "lag"
(默认)和{{ 1}}。有关使用情况的详情,请参阅type = "lead"
。
有了这个,我们可以做到:
?shift
答案 2 :(得分:2)
感谢Matthew Dowle的建议,我能够使用以下内容:
DT[,lagret:=DT[list(stock_id,date-1),logret,roll=TRUE][[3L]]]
结果是:
date stock_id logret lagret
1: 2011-01-01 1 0.001 NA
2: 2011-01-02 1 0.003 0.001
3: 2011-01-03 1 0.005 0.003
4: 2011-01-04 1 0.007 0.005
5: 2011-01-05 1 0.009 0.007
6: 2011-01-06 1 0.011 0.009
7: 2011-01-01 2 0.013 NA
8: 2011-01-02 2 0.015 0.013
9: 2011-01-03 2 0.017 0.015
10: 2011-01-04 2 0.019 0.017
11: 2011-01-05 2 0.021 0.019
12: 2011-01-06 2 0.023 0.021
13: 2011-01-01 3 0.025 NA
14: 2011-01-02 3 0.027 0.025
15: 2011-01-03 3 0.029 0.027
16: 2011-01-04 3 0.031 0.029
17: 2011-01-05 3 0.033 0.031
18: 2011-01-06 3 0.035 0.033