一组间隔(范围)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
我有一些索引,例如:
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