【问题标题】:Create lagged columns using data.table使用 data.table 创建滞后列
【发布时间】:2017-05-10 15:05:25
【问题描述】:

背景:
假设我有这个代码

library(data.table)

#reproducibility
set.seed(45L)

#make table
dt <- data.table(V1=c(1L,2L),
                 V2=LETTERS[1:3],
                 V3=round(rnorm(4),4),
                 V4 = 1:12)
dt

我得到的

> dt
    V1 V2      V3 V4
 1:  1  A  0.3408  1
 2:  2  B -0.7033  2
 3:  1  C -0.3795  3
 4:  2  A -0.7460  4
 5:  1  B  0.3408  5
 6:  2  C -0.7033  6
 7:  1  A -0.3795  7
 8:  2  B -0.7460  8
 9:  1  C  0.3408  9
10:  2  A -0.7033 10
11:  1  B -0.3795 11
12:  2  C -0.7460 12

我想追加创建 10 列 V3 的滞后。

问题:
有没有办法在“数据表”范式中做到这一点。

更多详情:
如果它是一个data.frame,那么我可以做一个循环。

dt <- as.data.frame(dt)


for(i in 1:10){
     dt <- cbind(dt, shift(x = dt[, 3], 
                           n = i, 
                           fill = NA, 
                           type = "lag"))
     names(dt)[ncol(dt)] <- sprintf("lag_%06d",i)
}

dt

我得到的:

> dt
   V1 V2      V3 V4 lag_000001 lag_000002 lag_000003 lag_000004 lag_000005 lag_000006 lag_000007 lag_000008 lag_000009 lag_000010
1   1  A  0.3408  1         NA         NA         NA         NA         NA         NA         NA         NA         NA         NA
2   2  B -0.7033  2     0.3408         NA         NA         NA         NA         NA         NA         NA         NA         NA
3   1  C -0.3795  3    -0.7033     0.3408         NA         NA         NA         NA         NA         NA         NA         NA
4   2  A -0.7460  4    -0.3795    -0.7033     0.3408         NA         NA         NA         NA         NA         NA         NA
5   1  B  0.3408  5    -0.7460    -0.3795    -0.7033     0.3408         NA         NA         NA         NA         NA         NA
6   2  C -0.7033  6     0.3408    -0.7460    -0.3795    -0.7033     0.3408         NA         NA         NA         NA         NA
7   1  A -0.3795  7    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408         NA         NA         NA         NA
8   2  B -0.7460  8    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408         NA         NA         NA
9   1  C  0.3408  9    -0.7460    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408         NA         NA
10  2  A -0.7033 10     0.3408    -0.7460    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408         NA
11  1  B -0.3795 11    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408
12  2  C -0.7460 12    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033     0.3408    -0.7460    -0.3795    -0.7033

必须有更优雅的方式。可以更快更有效地处理更大数据的东西。

现在,如果我想先执行此操作,在 V3 列上制作 10 个滞后,然后在 V4 上制作,而不预先假定它们的名称。我可以简单地制作嵌套的 for 循环,但我再次怀疑 data.table 有一些好的(很棒的?)可以提供。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    是的,shift 考虑了这种类型的用户需求。当shift 的参数n 是向量时,shift 将返回n 中每个班次的列表:

    dt[, sprintf("V3_lag_%06d", 1:10) := shift(V3, 1:10, type = 'lag')]
    dt[, sprintf("V4_lag_%06d", 1:10) := shift(V4, 1:10, type = 'lag')]
    
    #     V1 V2      V3 V4 V3_lag_000001 V3_lag_000002 V3_lag_000003 V3_lag_000004 V3_lag_000005
    #  1:  1  A  1.2322  1            NA            NA            NA            NA            NA
    # 2:  2  B  1.6094  2        1.2322            NA            NA            NA            NA
    # 3:  1  C  0.4016  3        1.6094        1.2322            NA            NA            NA
    # 4:  2  A -0.2730  4        0.4016        1.6094        1.2322            NA            NA
    # 5:  1  B  1.2322  5       -0.2730        0.4016        1.6094        1.2322            NA
    # 6:  2  C  1.6094  6        1.2322       -0.2730        0.4016        1.6094        1.2322
    # 7:  1  A  0.4016  7        1.6094        1.2322       -0.2730        0.4016        1.6094
    # 8:  2  B -0.2730  8        0.4016        1.6094        1.2322       -0.2730        0.4016
    # 9:  1  C  1.2322  9       -0.2730        0.4016        1.6094        1.2322       -0.2730
    # 10:  2  A  1.6094 10        1.2322       -0.2730        0.4016        1.6094        1.2322
    # 11:  1  B  0.4016 11        1.6094        1.2322       -0.2730        0.4016        1.6094
    # 12:  2  C -0.2730 12        0.4016        1.6094        1.2322       -0.2730        0.4016
    # V3_lag_000006 V3_lag_000007 V3_lag_000008 V3_lag_000009 V3_lag_000010 V4_lag_000001
    # 1:            NA            NA            NA            NA            NA            NA
    # 2:            NA            NA            NA            NA            NA             1
    # 3:            NA            NA            NA            NA            NA             2
    # 4:            NA            NA            NA            NA            NA             3
    # 5:            NA            NA            NA            NA            NA             4
    # 6:            NA            NA            NA            NA            NA             5
    # 7:        1.2322            NA            NA            NA            NA             6
    # 8:        1.6094        1.2322            NA            NA            NA             7
    # 9:        0.4016        1.6094        1.2322            NA            NA             8
    # 10:       -0.2730        0.4016        1.6094        1.2322            NA             9
    # 11:        1.2322       -0.2730        0.4016        1.6094        1.2322            10
    # 12:        1.6094        1.2322       -0.2730        0.4016        1.6094            11
    # V4_lag_000002 V4_lag_000003 V4_lag_000004 V4_lag_000005 V4_lag_000006 V4_lag_000007
    # 1:            NA            NA            NA            NA            NA            NA
    # 2:            NA            NA            NA            NA            NA            NA
    # 3:             1            NA            NA            NA            NA            NA
    # 4:             2             1            NA            NA            NA            NA
    # 5:             3             2             1            NA            NA            NA
    # 6:             4             3             2             1            NA            NA
    # 7:             5             4             3             2             1            NA
    # 8:             6             5             4             3             2             1
    # 9:             7             6             5             4             3             2
    # 10:             8             7             6             5             4             3
    # 11:             9             8             7             6             5             4
    # 12:            10             9             8             7             6             5
    # V4_lag_000008 V4_lag_000009 V4_lag_000010
    # 1:            NA            NA            NA
    # 2:            NA            NA            NA
    # 3:            NA            NA            NA
    # 4:            NA            NA            NA
    # 5:            NA            NA            NA
    # 6:            NA            NA            NA
    # 7:            NA            NA            NA
    # 8:            NA            NA            NA
    # 9:             1            NA            NA
    # 10:             2             1            NA
    # 11:             3             2             1
    # 12:             4             3             2
    

    【讨论】:

    • 仅供参考,不需要用c(f()) := 包装函数
    • @Frank,我一直认为在创建多个列时应该使用c()data.table 会先检查LHS 是否是一个函数吗?
    • 只有一种情况需要。为方便起见,DT[, x := ] 将创建一个名为 x 的列(不需要用引号括起来,如 "x" :=),但这意味着如果要动态定义 x,则必须用括号括起来,x = "col"; DT[, (x) := ] .
    • 哇! data.table 太性感了。我整晚(字面意思)在 data.frame 上运行了该死的东西,但没有完成。这实际上是在几分钟内完成的。 Data.table 非常性感。哇。
    【解决方案2】:

    也可以在 1 个data.table 电话中完成所有操作。如果您需要很多列,这可能特别有用:

    cols <- c("V3","V4")
    dt[, (paste0("lag_",rep(cols, each = 10), "_", rep(1:10, times = length(cols)))) := 
                unlist(lapply(.SD, function(x) shift(x, 1:10, type = "lag")), recursive = F), .SDcols = cols]
    

    paste0(...) 代码按照我们想要的方式设置列名,然后unlist(lapply(...)) 代码按照我们想要的顺序获取每列的滞后。要查看它们的工作原理,您可以单独运行它们(如果运行 unlist(lapply(...)),您必须将 dt[,c("V3","V4")] 替换为 .SD

    dt[,1:9]
    #    V1 V2      V3 V4 lag_V3_1 lag_V4_1 lag_V3_2 lag_V4_2 lag_V3_3
    # 1:  1  A  0.3408  1       NA       NA       NA       NA       NA
    # 2:  2  B -0.7033  2   0.3408        1       NA       NA       NA
    # 3:  1  C -0.3795  3  -0.7033        2   0.3408        1       NA
    # 4:  2  A -0.7460  4  -0.3795        3  -0.7033        2   0.3408
    # 5:  1  B  0.3408  5  -0.7460        4  -0.3795        3  -0.7033
    # 6:  2  C -0.7033  6   0.3408        5  -0.7460        4  -0.3795
    # 7:  1  A -0.3795  7  -0.7033        6   0.3408        5  -0.7460
    # 8:  2  B -0.7460  8  -0.3795        7  -0.7033        6   0.3408
    # 9:  1  C  0.3408  9  -0.7460        8  -0.3795        7  -0.7033
    #10:  2  A -0.7033 10   0.3408        9  -0.7460        8  -0.3795
    #11:  1  B -0.3795 11  -0.7033       10   0.3408        9  -0.7460
    #12:  2  C -0.7460 12  -0.3795       11  -0.7033       10   0.3408
    

    【讨论】:

    • 根据我的基准测试,一次调用的可读性较差,但比我的答案略快。 +1
    • 当然可读性较差,我只是认为如果他必须滞后很多不同的列可能会有所帮助(这样就不需要很多打字了)。但是,对于几列,我肯定会选择您的解决方案
    • 我将它包裹在一个循环中。我确实有很多专栏,但是哇。我认为 data.table 可能是我最好的新朋友......从数字上讲。
    • 这几乎对我有用,也许一些 data.table 更新改变了一些事情。下面贴出修改后的版本。
    【解决方案3】:

    Mike H. 的答案对我不起作用——我认为可能是由于 data.table 更新。修改后的形式是:

    lagcols <- c('test1','test2') #input column names
    
    lagcols2<- paste0("lag",  #output column names
      rep(lag, times = length(lagcols)),'_',
      rep(lagcols, each = length(lag)))
    
    lag <- c(1,2,10) #desired lags
    
    dt[, (lagcols2) :=  shift(.SD, lag), by=id]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-07
      • 2016-07-02
      • 1970-01-01
      • 2022-07-02
      • 2020-02-06
      相关资源
      最近更新 更多