【问题标题】:R data.table grouping for lagged regression用于滞后回归的 R data.table 分组
【发布时间】:2012-07-09 00:17:20
【问题描述】:

带有数据的表(它是一个 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_id 和日期。旨在重塑此数据表,以便我可以对所有 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 的情况下构建这个数据结构真的很棘手。

【问题讨论】:

  • 2011-04-012011-04-04 之间的延迟不是 1 天。
  • 您是绝对正确的,需要澄清一下——这是因为周末股市休市。所以它实际上滞后于前一个日期。
  • setkey(stockid,date)。然后在date-1 上使用:=roll 添加滞后列。然后按股票做回归。
  • 嗨,马修,哪个包裹滚进来了?我是 R 的新手,从 Matlab 转换而来。
  • 嗯。试试DT[,lagret:=DT[list(id,date-1),logret,roll=TRUE][[3L]]]。您使用的是哪个版本的data.table?一个完整的可重现示例会很好 - 可以粘贴到 R 会话中。

标签: r grouping data.table reshape


【解决方案1】:

由于 Alex 的评论,只是一些额外的注释。您难以理解这里发生的事情的原因是很多事情都是在一行中完成的。因此,分解事物总是一个好主意。

我们真正想要什么?我们想要一个新列lagret,在data.table中添加一个新列的语法如下:

DT[, lagret := xxx]

其中xxx 必须在lagret 列中填写您想要的任何内容。因此,如果我们只想要一个新列来为我们提供行,我们可以调用

DT[, lagret := seq(from=1, to=nrow(DT))]

这里,我们实际上想要logret 的滞后值,但是我们必须考虑这里有很多股票。这就是我们进行自连接的原因,即我们通过列stock_iddate 将data.table DT 与自身连接起来,但是由于我们想要每只股票的先前值,所以我们使用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 现在滞后一个周期。但我们实际上希望在DT 中的新列lagret 中使用它,所以我们只需通过调用[[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 日)。

【讨论】:

  • +10。自己不能更好地解释它。 [[3L]] ugliness(必须硬编码 3L 以忽略结果中的分组列)在实现 FR#1757 Add drop to [.data.table 时应该更快更方便。
  • 使用[,logret] 似乎比使用[[3L]] 更直观。有你不应该的理由吗?除了更直观之外,使用[,logret] 还允许您在将来更改列顺序,而无需更改列号引用。 (当然,如果列 names 发生变化,那么您必须更新列名引用,但至少应该更明显......)
  • 好点,我刚刚使用了[[3L]],因为这是 Matthew 的原始提议,在我的回答中,我想解释它是如何工作的。但是,我不确定您的选择是否一直有效。如果现在这样做,那绝对是更简洁的语法,我同意。
  • 杰出的解释!谢谢!
  • data.table 中一定发生了一些变化,因为这个答案似乎不起作用。似乎有一个错误——应该是DT[,lagret:=DT[list(stock_id,date-1),logret]]DT[,lagret:=DT[list(stock_id,date-1)][[3L]]],而不是DT[,lagret:=DT[list(stock_id,date-1),logret][[3L]]]
【解决方案2】:

更新:

在data.table的当前开发版本中,v1.9.5shift()实现了#965,目前有type = "lag"(默认)和type = "lead"两种类型。有关使用的更多信息,请参阅?shift

有了这个,我们可以简单地做到:

# type="lag" may be omitted, as it is the default.
require(data.table) ## 1.9.5+
DT[, lagret := shift(logret, 1L, type="lag"), by=stock_id]
#           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

【讨论】:

  • 如果您的日期有规律地间隔(即,如果它们没有“间隔”),这很好。接受的答案允许这样的差距。
  • 但这不会处理不规则的时间序列,并且会给出错误的滞后,对吗?
【解决方案3】:

感谢 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

【讨论】:

  • 好,很高兴有些东西有效。我已经提出FR#2142 在评论中为上述第一个更简洁的语法添加测试和示例。
  • 再次感谢@MatthewDowle data.table 一款出色的软件,希望当我为我的研究涉足它时,我会添加更多没有很好记录的场景。对编写它并指导我们新手的努力表示敬意。
  • 有人能解释一下这个答案是如何工作的吗?我很难理解发生了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-29
  • 1970-01-01
  • 2016-07-02
  • 2020-11-10
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
相关资源
最近更新 更多