在 data.table 中按组按不同范围过滤

Filtering by different ranges by group in data.table

我在 table 中有一些数据,我想进行非等值连接(我认为这是正确的术语)并针对不同的组按不同的范围对其进行过滤。在下面的示例中,我想过滤组“a”,以便它只有 returns 介于 1 和 20(含)之间的值和组“b”,所以它只有 returns 介于 80 和 100(含)之间的值).我的阅读建议 inrange 应该是要使用的项目。我知道如何在一般情况下使用它,但我不确定如何按组将其设置为具有不同范围的 运行。 (示例代码改编自 ?inrange

创建示例数据

set.seed(1234)
Y = data.table(a=sample(1:100,100), val=runif(100), group=c(rep("a",50),rep("b",50)))
range = data.table(group=c("a","b"),start = c(1,80), end = c(20,100))

尝试过滤

Y[inrange(a, range$start, range$end),,by=group]

这显然不起作用,而是将这些范围应用于整个数据集并抛出错误消息 Ignoring by= because j= is not supplied。我想我很清楚这不起作用,因为我没有在范围 table 和 Y 之间创建 'join',但我不知道如何制作两个 table s 通过 inrange.

进行分组交流

注意:实际上 a 中的值将是 posixct 日期时间,但为了简单起见,我在这里不使用它。

也许:

Y[range, K := TRUE, on = .(group, a >= start, a <= end)][!is.na(K),]
#         a        val  group      K
#     <int>      <num> <char> <lgcl>
#  1:     9 0.60189755      a   TRUE
#  2:     5 0.99874081      a   TRUE
#  3:    16 0.55512663      a   TRUE
#  4:     4 0.42944396      a   TRUE
#  5:    14 0.43101637      a   TRUE
#  6:     3 0.47880269      a   TRUE
#  7:     2 0.02220682      a   TRUE
#  8:     6 0.63891131      a   TRUE
#  9:     8 0.83470266      a   TRUE
# 10:    17 0.98304402      a   TRUE
# 11:    98 0.76785547      b   TRUE
# 12:    94 0.30766574      b   TRUE
# 13:    88 0.25814665      b   TRUE
# 14:    89 0.49954639      b   TRUE
# 15:    83 0.50892062      b   TRUE
# 16:    95 0.49443856      b   TRUE
# 17:    97 0.56695890      b   TRUE
# 18:    87 0.98970989      b   TRUE
# 19:    82 0.53190509      b   TRUE
# 20:   100 0.59662376      b   TRUE
#         a        val  group      K

还有其他方法可以做到这一点,但它们涉及重命名或信息丢失。例如,

  • left-join rangeY,我们失去 a:

    Y[range, on = .(group, a >= start, a <= end)]
    #         a        val  group   a.1
    #     <int>      <num> <char> <int>
    #  1:     1 0.60189755      a    20
    #  2:     1 0.99874081      a    20
    #  3:     1 0.55512663      a    20
    # ...
    # 18:    80 0.98970989      b   100
    # 19:    80 0.53190509      b   100
    # 20:    80 0.59662376      b   100
    #         a        val  group   a.1
    

    修复方法是将 Y$a 复制到一个新变量中,然后加入它:

    Y[,a1 := a][range, on = .(group, a1 >= start, a1 <= end)]
    #         a        val  group    a1  a1.1
    #     <int>      <num> <char> <int> <int>
    #  1:     9 0.60189755      a     1    20
    #  2:     5 0.99874081      a     1    20
    #  3:    16 0.55512663      a     1    20
    # ...
    # 18:    87 0.98970989      b    80   100
    # 19:    82 0.53190509      b    80   100
    # 20:   100 0.59662376      b    80   100
    #         a        val  group    a1  a1.1
    
  • left-join Yrange,我们将 a 复制到 startend 但没有明确的指示符过滤条件:

    range[Y, on = .(group, start <= a, end >= a)]
    #       group start   end        val
    #      <char> <int> <int>      <num>
    #   1:      a    28    28 0.85026492
    #   2:      a    80    80 0.23466126
    #   3:      a    22    22 0.98816745
    # ...
    #  98:      b    82    82 0.53190509
    #  99:      b   100   100 0.59662376
    # 100:      b    30    30 0.26388647
    #       group start   end        val
    

    一种补救方法是复制到另一个字段中,该字段将为我们提供我们需要能够过滤的合并指示符。但即便如此,我们也必须重命名才能重新获得 a 的数据:

    range[, K := TRUE][Y, on = .(group, start <= a, end >= a)][ !is.na(K), ]
    #      group start   end      K        val
    #     <char> <int> <int> <lgcl>      <num>
    #  1:      a     9     9   TRUE 0.60189755
    #  2:      a     5     5   TRUE 0.99874081
    #  3:      a    16    16   TRUE 0.55512663
    # ...
    # 18:      b    87    87   TRUE 0.98970989
    # 19:      b    82    82   TRUE 0.53190509
    # 20:      b   100   100   TRUE 0.59662376
    #      group start   end      K        val