【问题标题】:Select values within/outside of a set of intervals (ranges) R选择一组区间(范围)内/外的值 R
【发布时间】:2015-12-29 02:50:34
【问题描述】:

我有某种索引,例如:

index <- 1:100

我还有一个“排除区间”/范围列表

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) 来计算我的间隔,我找不到执行此操作的内置函数。

【问题讨论】:

  • 您的范围是否总是不重叠且按递增顺序排列?
  • 我使用 library(intervals) - interval_union() 来确保我的间隔不重叠。这似乎也对它们进行了排序。

标签: r subset intervals


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 如果index 变成一组随机的、连续的数字,例如index &lt;- rnorm(100)*1000?
    • @Ant 代替setdiff,我们使用从unlist 返回的数字索引向量index[-unlist(with(exclude, Map(:, start, end)))]index[setdiff(seq_along(index), unlist(with(exclude, Map(:, start, end))))]
    • 问题是,例如,index 值 5.255 确实会落入我的排除区间,但不会被排除 - 您建议的解决方案只会删除整数值。我想我犯了一个错误,称它为“索引”并赋予它整数值,而事实上,我得到的更像是一堆随机数,我试图排除那些落在特定区间内的数字.您的回答对我的问题是正确的,是我没有很好地表达我的问题并且可能过于简单化了。那么,这可能值得提出一个不同的问题。谢谢。
    • @Ant 请将其作为一个新问题发布。
    【解决方案3】:

    另一种方法

    > 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多