可以在data.table中结合逻辑索引和位置索引吗?

时间:2019-04-19 19:13:28

标签: r indexing data.table

我正在尝试逐组遍历data.table,以便在每个子组内有条件地为每行分配值。我可以选择所需的行,但是无法更新所选行中的目标变量。

我认为这可能是由于我必须将data.table切片两次。我正在使用一个名为data.table的{​​{1}},该列具有dtgroupcenterdate列。此处的目标是使非中心记录(也称为var)的var的值与其最近的中心记录(按日期差)center==0相匹配。假设center==1是该行的位置索引,我想基于条件过滤来更新记录,然后在子组i中搜索date

gp

但是当我跑步

dt[group == gp][i, var:= "new value"] 

变量dt[group == gp][i, var] 似乎没有变化,也就是返回了var

其他信息

上面的命令在for循环中,也许我没有在这里使用最佳实践。如果有人对以下for循环分享他/她的意见,我将不胜感激。谢谢。

"old value"

我知道data.table中有for( gp in unique(dt$group)){ tmp = dt[group==gp] for( i in 1:nrow(tmp)){ new_val = tmp[center==1][which.min(abs(tmp[i, date]-tmp[center==1, date]),var] dt[group == gp][i, var:= new_val] } } set。但是我不知道如何使用.by语法轻松地将条件搜索功能应用于每个子组。也许我可以在dt[, j=somefunction ,by=group]上加一个小号,但是它比for循环快得多吗?性能的提高值得丧失可读性吗?

编辑

在下面的评论部分中,我找到了在data.table中同时结合逻辑索引和位置索引的技巧:

.SD

有关使用for循环是否是一个好主意的问题仍未得到解答。任何输入将不胜感激!

示例

假设原始dt(按组和日期排序)如下所示:

dt[which(group == gp)[i], var := new_val]

我希望更新的dt为:

group center  date     var
  1     0     10-01    NA
  1     1     10-02    val1
  1     0     10-03    NA
  1     1     11-05    val2
  2     1     10-02    val3

比方说,我们这里大约有10,000个组,每个组最多可以有1000行。

1 个答案:

答案 0 :(得分:1)

对于此问题,您可能需要考虑使用滚动联接,如下所示:

dt[center==0L, var := dt[center!=0L][.SD, var, on=.(group, date), roll="nearest"]]

说明:

  1. dt[center==0L过滤要更新的行。

  2. var :=告诉data.table,这是要更新的列。

  3. dt[center!=0L]过滤中心不为0的行。

  4. dt[center!=0L][.SD, on=.(group, date)]将步骤1(.SD)中的行与步骤3中的行连接起来,, var,选择此列作为输出。

  5. 有关?data.table参数的帮助,请参见roll。当roll='nearest'时,它将查找联接中最接近的date。请注意,滚动键应始终是on参数中的最后一个元素。

输出:

   group center       date  var
1:     1      0 2018-10-01 val1
2:     1      1 2018-10-02 val1
3:     1      0 2018-10-03 val1
4:     1      1 2018-11-05 val2
5:     2      1 2018-10-02 val3

数据:

library(data.table)
dt <- fread("group center  date     var
1     0     2018-10-01    NA
1     1     2018-10-02    val1
1     0     2018-10-03    NA
1     1     2018-11-05    val2
2     1     2018-10-02    val3")
dt[, date := as.Date(date, format="%Y-%m-%d")]