一组间隔(范围)R 的 Select 值 within/outside

Select values within/outside of a set of intervals (ranges) R

我有一些索引,例如:

index <- 1:100

我还有一个 "exclusion intervals" / 范围

的列表
exclude <- data.frame(start = c(5,50, 90), end = c(10,55, 95))

  start end
1     5  10
2    50  55
3    90  95

我正在寻找一种有效的方法(在 R 中)删除属于 exclude 数据框范围内的所有索引

因此所需的输出将是:

1,2,3,4,  11,12,...,48,49,  56,57,...,88,89,  96,97,98,99,100

我可以迭代地执行此操作:遍历每个排除区间(使用 ddply)并迭代地删除落在每个区间内的索引。但是有没有更有效的方法(或功能)来做到这一点?

我正在使用 library(intervals) 来计算我的间隔,我找不到可以执行此操作的内置函数。

我们可以使用Map获取'start''end'列中相应元素的序列,unlist创建vector并使用setdiff 获取不在 vector 中的 'index' 的值。

setdiff(index,unlist(with(exclude, Map(`:`, start, end))))
#[1]   1   2   3   4  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25
#[20]  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44
#[39]  45  46  47  48  49  56  57  58  59  60  61  62  63  64  65  66  67  68  69
#[58]  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88
#[77]  89  96  97  98  99 100

或者我们可以先用rep再用setdiff.

i1 <- with(exclude, end-start) +1L
setdiff(index,with(exclude, rep(start, i1)+ sequence(i1)-1))

注意:两种方法return需要排除的索引位置。在上面的例子中,原始向量 ('index') 是一个序列,所以我使用了 setdiff。如果包含随机元素,适当使用位置向量,即

index[-unlist(with(exclude, Map(`:`, start, end)))]

index[setdiff(seq_along(index), unlist(with(exclude, 
                       Map(`:`, start, end))))]

另一种方法

> index[-do.call(c, lapply(1:nrow(exclude), function(x) exclude$start[x]:exclude$end[x]))]
 [1]   1   2   3   4  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30
[25]  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  56  57  58  59  60
[49]  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84
[73]  85  86  87  88  89  96  97  98  99 100

另一种看起来有效的方法可能是:

starts = findInterval(index, exclude[["start"]])
ends = findInterval(index, exclude[["end"]])# + 1L) ##1 needs to be added to remove upper 
                                                        ##bounds from the 'index' too
index[starts != (ends + 1L)] ##a value above a lower bound and 
                                       ##below an upper is inside that interval

这里的主要优点是不需要创建包含所有区间元素的向量,而且它可以处理特定区间内的任何一组值;例如:

set.seed(101); x = round(runif(15, 1, 100), 3)
x
# [1] 37.848  5.339 71.259 66.111 25.736 30.705 58.902 34.013 62.579 55.037 88.100 70.981 73.465 93.232 46.057
x[findInterval(x, exclude[["start"]]) != (findInterval(x, exclude[["end"]]) + 1L)]
# [1] 37.848 71.259 66.111 25.736 30.705 58.902 34.013 62.579 55.037 88.100 70.981 73.465 46.057