【问题标题】:Possible to combine logical and position indexing in data.table?可以在 data.table 中结合逻辑和位置索引吗?
【发布时间】:2019-04-19 19:13:27
【问题描述】:

我正在尝试按组遍历 data.table 以在每个子组内有条件地为每一行分配值。我可以选择我想要的行,但我无法更新我选择的行中感兴趣的变量。

我认为这可能是因为我必须对 data.table 进行两次切片。我正在使用一个名为dtdata.table,它有groupcenterdatevar 列。这里的目标是将非中心记录的var 的值也称为center==0center==1 最接近的(就日期差异而言)中心记录。假设i 是行的位置索引,我想根据条件过滤更新记录,然后在子组gp 中搜索date

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

但是当我运行时

dt[group == gp][i, var] 

变量var 似乎没有改变,也就是返回"old value"

其他信息

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

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] 
 }
}

我知道 data.table 中的 set.by。但我不知道如何使用dt[, j=somefunction ,by=group] 语法轻松地将条件搜索功能应用于每个子组。也许我可以在.SD 上放一个 sapply,但它比 for 循环快得多吗?性能的提升是否值得可读性的损失?

编辑

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

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

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

示例

假设原始 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

我希望更新后的 dt 是:

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

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

【问题讨论】:

  • @IceCreamToucan 感谢您的评论!这招奏效了哈哈。
  • @markus 示例为问题的第二部分更新。

标签: r indexing data.table


【解决方案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)] left 将第 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")]

【讨论】:

  • 您好,此解决方案适用于发布的示例!除了 ?data.table 中的描述之外,您知道我在哪里可以阅读更多(示例)roll 吗?
  • 或者你能添加一些解释/分解这个单行语法吗?将不胜感激!
  • 您可能想先从 data.table 小插曲开始?然后可能在线搜索 data.table 滚动连接。一个有用的博客:r-bloggers.com/understanding-data-table-rolling-joins
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-28
  • 2023-01-10
  • 1970-01-01
  • 2017-09-16
  • 2021-10-13
  • 1970-01-01
  • 2023-03-06
相关资源
最近更新 更多