折叠具有重叠范围的行

Liz*_*iza 6 r rows subset overlap overlapping

我有一个包含开始和结束时间的data.frame:

ranges<- data.frame(start = c(65.72000,65.72187, 65.94312,73.75625,89.61625),stop = c(79.72187,79.72375,79.94312,87.75625,104.94062))

> ranges
     start      stop
1 65.72000  79.72187
2 65.72187  79.72375
3 65.94312  79.94312
4 73.75625  87.75625
5 89.61625 104.94062
Run Code Online (Sandbox Code Playgroud)

在此示例中,第2行和第3行中的范围完全在第1行的"start"和第4行的"stop"之间的范围内.因此,重叠范围1-4应折叠为一个范围:

> ranges
     start      stop
1 65.72000  87.75625
5 89.61625 104.94062
Run Code Online (Sandbox Code Playgroud)

我试过这个:

mdat <- outer(ranges$start, ranges$stop, function(x,y) y > x)
mdat[upper.tri(mdat)|col(mdat)==row(mdat)] <- NA
mdat
Run Code Online (Sandbox Code Playgroud)

而现在我只需要弄清楚如何结合所有真实的,但不确定它是否是最好的方法

Psi*_*dom 11

你可以试试这个:

library(dplyr)
ranges %>% 
       arrange(start) %>% 
       group_by(g = cumsum(cummax(lag(stop, default = first(stop))) < start)) %>% 
       summarise(start = first(start), stop = max(stop))

# A tibble: 2 × 3
#      g    start      stop
#  <int>    <dbl>     <dbl>
#1     0 65.72000  87.75625
#2     1 89.61625 104.94062
Run Code Online (Sandbox Code Playgroud)

  • 这完全解决了我的问题,但我还不太明白.当我再次通过代码试图辨别它的魔力时,感谢你的小提琴技巧. (2认同)
  • @Jemus42 代码首先按“start”列对行进行排序。`lag(stop)` 添加一个假想列,其中包含之前的 `stop` 值。“cummax”将保留之前“stop”值的最高值,以便您可以与“start”列进行比较。如果“start”值大于前面“stop”值的最大值,则您属于新组。`cumsum` 将累积 `TRUE`,以便您获得每个组的标识符 (`g`)。`summarise` 将按组 id 进行聚合,并获取区间的起始值和结束值。非常聪明的解决方案@Psidom :) (2认同)

lmo*_*lmo 5

这是一个data.table解决方案

library(data.table)
setDT(ranges)
ranges[, .(start=min(start), stop=max(stop)),
       by=.(group=cumsum(c(1, tail(start, -1) > head(stop, -1))))]
   group    start      stop
1:     1 65.72000  87.75625
2:     2 89.61625 104.94062
Run Code Online (Sandbox Code Playgroud)

这里,通过检查先前的开始是否大于停止然后使用来构建组cumsum.在每组中,计算最小开始和最大停止.


San*_*Dey 5

使用base Rmelt / unstack,让我们添加一些日期以使问题更有趣和通用:

ranges<- data.frame(start = c(65.72000,65.72187, 65.94312,73.75625,89.61625,105.1,104.99),stop = c(79.72187,79.72375,79.94312,87.75625,104.94062,110.22,108.01))
ranges
#      start      stop
#1  65.72000  79.72187
#2  65.72187  79.72375
#3  65.94312  79.94312
#4  73.75625  87.75625
#5  89.61625 104.94062
#6 105.10000 110.22000
#7 104.99000 108.01000

library(reshape2)
ranges <- melt(ranges)
ranges <- ranges[order(ranges$value),]
ranges
#   variable     value
#1     start  65.72000
#2     start  65.72187
#3     start  65.94312
#4     start  73.75625
#8      stop  79.72187
#9      stop  79.72375
#10     stop  79.94312
#11     stop  87.75625
#5     start  89.61625
#12     stop 104.94062
#7     start 104.99000
#6     start 105.10000
#14     stop 108.01000
#13     stop 110.22000
Run Code Online (Sandbox Code Playgroud)

从上面可以看出,(有一个合理的假设,我们有一个起始值是所有值中最小的一个,并且一个停止值是所有值中最大的一个),问题就减少到找到stop后面跟着的模式start在连续的行中,除了第一行和最后一行之外,这将是我们(找到重叠范围)的唯一兴趣点.以下代码实现了:

indices <- intersect(which(ranges$variable=='start')-1, which(ranges$variable=='stop'))
unstack(ranges[c(1, sort(c(indices, indices+1)), nrow(ranges)),], value~variable)
#      start      stop
#1  65.72000  87.75625
#2  89.61625 104.94062
#3 104.99000 110.22000
Run Code Online (Sandbox Code Playgroud)