子集由多个范围组成

时间:2017-04-26 18:26:13

标签: r range data.table subset

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

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

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

任何建议表示赞赏!谢谢!

3 个答案:

答案 0 :(得分:5)

如果您拥有data.table的最新CRAN版本,则可以使用非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]

答案 1 :(得分:5)

使用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

答案 2 :(得分: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%的矢量化扩展。