【问题标题】:How to efficiently find last preceding row with nonzero value in R data.table如何有效地在 R data.table 中找到具有非零值的最后一行
【发布时间】:2019-09-21 15:15:40
【问题描述】:

简介

我正在尝试找到最佳方法,如何在给定列中找到具有非零值的最后一行,并在该行上返回不同列的值。我想在 R data.table 中执行此操作,并且正在寻找该操作的最大效率。

示例

让我们有一个像这样的数据表:

set.seed(123)
DT = data.table(x=rep(c("b","a","c"),each=6),
                y=rep(1:6, 3),
                z = rbinom(18, 1, 0.3))

这给了我们以下数据表:

    x y z
 1: b 1 0
 2: b 2 1
 3: b 3 0
 4: b 4 1
 5: b 5 1
 6: b 6 0
 7: a 1 0
 8: a 2 1
 9: a 3 0
10: a 4 0
11: a 5 1
12: a 6 0
13: c 1 0
14: c 2 0
15: c 3 0
16: c 4 1
17: c 5 0
18: c 6 0

现在,该表针对 x 列中的每个值按 y 列排序。对于由x 列中的值给出的每个组,我想创建一个列,该列将为我从最后一个非零值z 的行中为每一行提供y 的值。

现在我对每个 y 使用 lapply 并按 x 分组,这给出了所需的结果:

DT[, list(y,
          z, 
          output = lapply(y, function(x) max(y[z != 0 & y <= x]))
          ), 
   by = 'x']

问题

我可以让示例中的代码更高效吗?

【问题讨论】:

  • 我已经测试了下面建议的滚动连接和非 equi 连接,结果证明在我的场景中滚动连接更快。不能说是因为设置还是一般情况

标签: r data.table


【解决方案1】:

你可以试试nafill:

# create a dummy column that is only populated for nonzero z (and hence NA elsewhere)
DT[z != 0, y_copy := y]
# nafill on this column using LOCF strategy by group:
DT[ , ans := nafill(y_copy, type = 'locf'), by = x][]
#     x y z y_copy ans
#  1: b 1 0     NA  NA
#  2: b 2 1      2   2
#  3: b 3 0     NA   2
#  4: b 4 1      4   4
#  5: b 5 1      5   5
#  6: b 6 0     NA   5
#  7: a 1 0     NA  NA
#  8: a 2 1      2   2
#  9: a 3 0     NA   2
# 10: a 4 0     NA   2
# 11: a 5 1      5   5
# 12: a 6 0     NA   5
# 13: c 1 0     NA  NA
# 14: c 2 0     NA  NA
# 15: c 3 0     NA  NA
# 16: c 4 1      4   4
# 17: c 5 0     NA   4
# 18: c 6 0     NA   4

目前,nafill 是一个仅限开发的功能(data.table 1.12.3+),但 1.12.4 应该会在接下来的一两周内在 CRAN 上发布。目前,您可以使用install.packages('data.table', type = 'source', repos = 'http://Rdatatable.github.io/data.table') 安装它

如果您不想创建 y_copy,可以使用 is.na&lt;- 内联执行此操作:

DT[ , ans := nafill(`is.na<-`(y, z == 0), type = 'locf'), by = x]

这将是低效的,因为z==0 是按组重复计算的(而不是作为单个向量);您可以在第一步中执行此操作:

DT[ , z_zero := z == 0]

但这意味着另一个虚拟列(如果ynumericcharactercomplex,则存储空间少于y_copy

【讨论】:

  • 或者使用 gitlab repo url 从二进制文件安装,这样就不需要在 windows 上安装 Rtools
【解决方案2】:

使用滚动连接的另一种选择:

DT[, output:= DT[z==1][.SD, on=.(x, y), roll=Inf, x.y]]

输出:

    x y z output
 1: b 1 0     NA
 2: b 2 1      2
 3: b 3 0      2
 4: b 4 1      4
 5: b 5 1      5
 6: b 6 0      5
 7: a 1 0     NA
 8: a 2 1      2
 9: a 3 0      2
10: a 4 0      2
11: a 5 1      5
12: a 6 0      5
13: c 1 0     NA
14: c 2 0     NA
15: c 3 0     NA
16: c 4 1      4
17: c 5 0      4
18: c 6 0      4

【讨论】:

    【解决方案3】:

    非等连接选项

    library(data.table)
    library(zoo)
    DT[DT[z!=0, .(y1 = y, x)], output := y1, on = .(x, y <= y1), 
             mult = 'last'][, output := na.locf0(output), x]
    DT
    #    x y z output
    # 1: b 1 0     NA
    # 2: b 2 1      2
    # 3: b 3 0      2
    # 4: b 4 1      4
    # 5: b 5 1      5
    # 6: b 6 0      5
    # 7: a 1 0     NA
    # 8: a 2 1      2
    # 9: a 3 0      2
    #10: a 4 0      2
    #11: a 5 1      5
    #12: a 6 0      5
    #13: c 1 0     NA
    #14: c 2 0     NA
    #15: c 3 0     NA
    #16: c 4 1      4
    #17: c 5 0      4
    #18: c 6 0      4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 2016-10-13
      • 1970-01-01
      相关资源
      最近更新 更多