首页 > 解决方案 > R - 在 data.table 中的多个列上应用 diff() 函数或等效的自定义函数

问题描述

目前有一个data.table大致如下所示:

ID   Date         Var1   Var2   Var3   Var4
1    2020-03-01   AB     A33    250    12
1    2020-04-01   B      B25    NA     14
1    2020-05-01   AB     A44    270    20
1    2020-06-01   AC     C33    9     13
2    2019-09-01   X      C55    280    11
2    2019-10-01   K      C89    120    12
2    2019-11-01   A      C89    320    NA
2    2019-12-01   AB     A88    200    25

这个数据表存储了键ID和一些对应的变量。有些是 type char,有些是 type numeric。该表已排序,setkey(dt, ID, Date)我想计算每个 ID 中每个数字变量的滞后差。

在我的数据中,我在看起来像这样的向量中提取了数字列。

cols <- c("Var3", "Var4")
cols_indx <- c(5:6) 

然后,我想将具有数字变量滞后差异的新列添加Var5Var6我的 data.tabledt中。

我尝试:

# Doesn't work    
as.data.frame(lapply(dt[ , cols, with = FALSE], diff, lag = 1))
as.data.frame(lapply(dt[ , cols_indx, with = FALSE], diff, lag = 1))
as.data.frame(lapply(dt[ , .SD, .SDcols = cols], diff, lag = 1))
as.data.frame(lapply(dt[ , .SD, .SDcols = cols_indx], diff, lag = 1))

在我的数据中没有一个有效并导致r[i1] - r[-length(r):-(length(r) - lag + 1L)]: non-numeric argument for binary operator。我似乎无法弄清楚是什么原因造成的,尤其是因为我在这段代码中的任何地方都没有看到二进制运算符。

但是,一旦我明确说明 colnames 或 col 索引,一切正常。这是为什么?在我的情况下,我需要移动一个超过 250 列的长 data.table,然后计算滞后差异或所有这些列以及多个滞后间隔的所有列。手动定义所有选定的列是不可管理的。我在这里想念什么?

# Works    
as.data.frame(lapply(dt[ , 5:6], diff, lag = 1))
as.data.frame(lapply(financials.dt[ , c("Var4", "Var5")], diff, lag = 1))

此外,还缺少一个步骤。我想计算每个组内的滞后差异(由 定义ID)。当我尝试diff使用自定义函数时,都会抛出类似的错误。

i <- 1
lag_names_diff <- paste(cols, "Lag", i, "d", sep = "_")

dt[ , (lag_names_diff) := lapply(.SD, function(x) x - shift(x, (i), type = "lag")),
       .SDcols = cols, by = ID] 
# Error 1:
# r[i1] - r[-length(r):-(length(r) - lag + 1L)] : non-numeric argument for binary operator

# or

dt[ , (lag_names_diff) := lapply(.SD, diff, x = cols, lag = i, differences = 1),
      .SDcols = cols, by = ID]
# Error 2:
# x - shift(x, (i), type = "lag") : non-numeric argument for binary operator

...一切都因错误消息而崩溃。我似乎无法弄清楚是什么原因造成的。非常感谢任何指针。

标签: rdata.table

解决方案


该错误似乎是因为diff(any_vector)返回一个向量,但长度比any_vector. 看到这个

diff(1:5)
[1] 1 1 1 1

因此,如果diff要应用于表中的任何变量,则必须在结果中添加一个元素,无论是在结束时还是在开始时。尽管我不确定您的预期结果,但我仍然假设这一点。(我添加NA到结果向量的开头。0如果需要,您也可以添加。

library(dplyr)
df %>% mutate(across(cols, ~c(NA, diff(.)), .names = "{.col}_diff"))

  ID       Date Var1 Var2 Var3 Var4 Var3_diff Var4_diff
1  1 2020-03-01   AB  A33  250   12        NA        NA
2  1 2020-04-01    B  B25   NA   14        NA         2
3  1 2020-05-01   AB  A44  270   20        NA         6
4  1 2020-06-01   AC  C33    9   13      -261        -7
5  2 2019-09-01    X  C55  280   11       271        -2
6  2 2019-10-01    K  C89  120   12      -160         1
7  2 2019-11-01    A  C89  320   NA       200        NA
8  2 2019-12-01   AB  A88  200   25      -120        NA

或者如果ID需要分组

df %>% group_by(ID) %>%
  mutate(across(cols, ~c(NA, diff(.)), .names = "{.col}_diff"))

# A tibble: 8 x 8
# Groups:   ID [2]
     ID Date       Var1  Var2   Var3  Var4 Var3_diff Var4_diff
  <int> <chr>      <chr> <chr> <int> <int>     <int>     <int>
1     1 2020-03-01 AB    A33     250    12        NA        NA
2     1 2020-04-01 B     B25      NA    14        NA         2
3     1 2020-05-01 AB    A44     270    20        NA         6
4     1 2020-06-01 AC    C33       9    13      -261        -7
5     2 2019-09-01 X     C55     280    11        NA        NA
6     2 2019-10-01 K     C89     120    12      -160         1
7     2 2019-11-01 A     C89     320    NA       200        NA
8     2 2019-12-01 AB    A88     200    25      -120        NA

推荐阅读