【问题标题】:How do I find ranges of successive numbers in a vector in R如何在R中的向量中找到连续数字的范围
【发布时间】:2016-03-16 16:31:33
【问题描述】:

我在 R 中有一个向量:

data <- c(1,4,6,7,8,9,20,30,31,32,33,34,35,60)

我想要的是找到比 3 个连续值更长的连续拉伸的开始和结束。即:

start end
3  6  (stretch 6-9)
8 13 (stretch 30-35

我不知道怎么去那里。

【问题讨论】:

  • 也许你看看rle() 和滞后的差异。如果它们是连续值,则滞后差将为 1。使用 rle() 在其中查找 1 的序列

标签: r


【解决方案1】:

@eddi's answer 到我的类似问题...

runs = split(seq_along(data), cumsum(c(0, diff(data) > 1)))
lapply(runs[lengths(runs) > 1], range)

# $`2`
# [1] 3 6
# 
# $`4`
# [1]  8 13

它是如何工作的

  • seq_along(data)data 的索引,来自 1..length(data)
  • c(0, diff(data) &gt; 1) 在每个索引处都有一个 1,其中 data “跳跃”
  • cumsum(c(0, diff(data) &gt; 1)) 是跳跃之间连续运行的标识符

所以runs 是将data 的索引划分为data 的值是连续的运行。

【讨论】:

  • 这是一个很好的答案,如果有点微妙而没有随附的解释
  • 要使其看起来像 OP 所需的输出,您可以执行以下操作:df &lt;- as.data.frame(do.call(rbind, lapply(runs[lengths(runs) &gt; 1], range))); names(df) &lt;- c("start","end"),尽管未明确指定所需的输出
  • 这正是我想要的。一位 matlab 同事在一个 matlab 论坛中提出了类似的东西。 nl.mathworks.com/matlabcentral/answers/…
  • @user1712989 酷。我在 r 之前很长时间学习了 matlab,所以我想它可能仍然会影响我的方法:)
【解决方案2】:

所以,首先取 a 的 diff 并对其进行运行长度序列。然后,起点是2s之前的索引,终点是它们的负差……很难解释,只需单步执行代码并检查一下。这在 (1, 3, 4, 7, 9) 中找不到两个... 的序列,例如 (3,4)。我必须将remove 部分包含在两个偏离...(1、3、5、7)的序列中。那些没有被正确捕获。无论如何,有趣的运动。我希望有人可以做得更好。这有点乱……

data <- c(1,4,6,7,8,9,20,30,31,32,33,34,35,60)
a <- sequence(rle(diff(data))$lengths)
starts <- which(a==2) - 1
ends <- which(diff(a)<0) + 1
remove <- starts[starts %in% (ends-2)]
starts <- starts[!starts %in% remove]
ends <- ends[!ends %in% (remove+2)]
if(length(ends) < length(starts)) ends <- c(ends, length(data))
> starts
[1] 3 8
> ends
[1]  6 13
> 

【讨论】:

    【解决方案3】:

    这是一个严重依赖 ?diff 的基本 R 解决方案:

    data <- c(1,4,6,7,8,9,20,30,31,32,33,34,35,60)
    
    diff1 <- diff(data[1:(length(data)-1)]) # lag 1 difference
    diff2 <- diff(data, 2) # lag 2 difference
    
    # indices of starting consecutive stretches -- these will overlap
    start_index <- which(diff1==1 & diff2==2)
    end_index <- start_index + 2
    
    # notice that these overlap:
    data.frame(start_index, end_index)
    
    # To remove overlap:
    # We can remove *subsequent* consecutive start indices
    #           and *initial* consecutive end indices
    
    start_index_new <- start_index[which(c(0, diff(start_index))!=1)]
    end_index_new <- end_index[which(c(diff(end_index), 0) != 1)]
    data.frame(start_index_new, end_index_new)
    
    #   start_index_new end_index_new
    # 1               3             6
    # 2               8            13
    

    Cory 的答案很棒——这个答案可能更容易理解,因为您基本上是在检查位置 i、位置 i+1 的值多 1 和位置 i + 2 的情况有 2 个以上的值。您以此为基础构建范围,然后将您的范围与另一个 diff 函数合并。在我看来,这有点简单。

    您还可以使用诸如 zoo 之类的软件包来帮助您获得滚动差异。

    【讨论】:

      猜你喜欢
      • 2022-11-07
      • 2014-09-20
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多