【问题标题】:Subset by multiple ranges [duplicate]多个范围的子集[重复]
【发布时间】:2017-09-24 07:26:05
【问题描述】:

我想获取一个介于多个范围之间的值的列表。

library(data.table)
values <- data.table(value = c(1:100))
range <-  data.table(start = c(6, 29, 87), end = c(10, 35, 92)) 

我需要结果仅包含介于这些范围之间的值:

 results <- c(6, 7, 8, 9, 10, 29, 30, 31, 32, 33, 34, 35, 87, 88, 89, 90, 91, 92)

我目前正在使用 for 循环执行此操作,

results <- data.table(NULL)
for (i in 1:NROW(range){ 
          results <- rbind(results, 
              data.table(result = values[value >= range[i, start] & 
                 value <= range[i, end], value]))}

但是实际数据集非常大,我正在寻找一种更有效的方法。

欢迎提出任何建议!谢谢!

【问题讨论】:

    标签: r range data.table subset


    【解决方案1】:

    如果您拥有最新的 CRAN 版本的 data.table,则可以使用非 equi 连接。例如,您可以创建一个索引,然后您可以使用它来对原始数据进行子集化:

    idx <- values[range, on = .(value >= start, value <= end), which = TRUE]
    # [1]  6  7  8  9 10 29 30 31 32 33 34 35 87 88 89 90 91 92
    values[idx]
    

    【讨论】:

      【解决方案2】:

      使用data.table的非等连接可能性:

      values[range, on = .(value >= start, value <= end), .(results = x.value)]
      

      给出:

          results
       1:       6
       2:       7
       3:       8
       4:       9
       5:      10
       6:      29
       7:      30
       8:      31
       9:      32
      10:      33
      11:      34
      12:      35
      13:      87
      14:      88
      15:      89
      16:      90
      17:      91
      18:      92
      

      或者根据@Henrik 的建议:values[value %inrange% range]。这也适用于具有多列的 data.table:

      # create new data
      set.seed(26042017)
      values2 <- data.table(value = c(1:100), let = sample(letters, 100, TRUE), num = sample(100))
      
      > values2[value %inrange% range]
          value let num
       1:     6   v  70
       2:     7   f  77
       3:     8   u  21
       4:     9   x  66
       5:    10   g  58
       6:    29   f   7
       7:    30   w  48
       8:    31   c  50
       9:    32   e   5
      10:    33   c   8
      11:    34   y  19
      12:    35   s  97
      13:    87   j  80
      14:    88   o   4
      15:    89   h  65
      16:    90   c  94
      17:    91   k  22
      18:    92   g  46
      

      【讨论】:

      • 我是否忽略了某些东西,或者这对于“值”表中的多/多列的情况是不切实际的?即是否有一些不列出列的简单方法?
      • 使用便捷功能%inrange%:values[value %inrange% range]
      • @Henrik 非常好!将其包含在我的答案中(如果您想将其发布为答案:继续,我将在此处将其删除)
      • @Henrik,确实如此。虽然您的问题仍然没有直接答案,但我相信我的答案中的方法可以用作另一种解决方法(可能不明确存储索引)
      • @Henrik,如果我能找到 which=TRUE 的方法,我会这样做
      【解决方案3】:

      这是使用lapply%between% 的一种方法

      rbindlist(lapply(seq_len(nrow(range)), function(i) values[value %between% range[i]]))
      

      此方法循环遍历范围 data.table 并根据范围中的变量在每次迭代中子集值。 lapply 返回一个列表,rbindlist 将其构造为 data.table。如果您需要矢量,请将rbindlist 替换为unlist


      基准

      为了检查给定数据上每个建议的速度,我进行了快速比较

      microbenchmark(
        lmo=rbindlist(lapply(seq_len(nrow(range)), function(i) values[value %between% range[i]])),
        dd={idx <- values[range, on = .(value >= start, value <= end), which = TRUE]; values[idx]},
        jaap=values[range, on = .(value >= start, value <= end), .(results = x.value)],
        inrange=values[value %inrange% range])
      

      返回

      Unit: microseconds
          expr      min        lq      mean    median       uq      max neval cld
           lmo 1238.472 1460.5645 1593.6632 1520.8630 1613.520 3101.311   100   c
            dd  688.230  766.7750  885.1826  792.8615  825.220 3609.644   100  b 
          jaap  798.279  897.6355  935.9474  921.7265  970.906 1347.380   100  b 
       inrange  463.002  518.3110  563.9724  545.5375  575.758 1944.948   100 a 
      

      正如所料,我的循环解决方案比其他解决方案慢很多。但是,明显的赢家是%inrange%,它本质上是%between% 的矢量化扩展。

      【讨论】:

        猜你喜欢
        • 2019-09-18
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 2014-03-11
        • 2020-09-06
        • 2014-02-17
        • 2016-09-01
        • 1970-01-01
        相关资源
        最近更新 更多