首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何平整/合并重叠时间段

如何平整/合并重叠时间段
EN

Stack Overflow用户
提问于 2015-03-09 08:58:01
回答 4查看 6.2K关注 0票数 20

我有大量的时间段数据集,由“开始”和“结束”列定义。有些时期重叠。

我想合并(扁平/合并/折叠)所有重叠的时间段,使之有一个“开始”值和一个“结束”值。

一些示例数据:

代码语言:javascript
运行
复制
  ID      start        end
1  A 2013-01-01 2013-01-05
2  A 2013-01-01 2013-01-05
3  A 2013-01-02 2013-01-03
4  A 2013-01-04 2013-01-06
5  A 2013-01-07 2013-01-09
6  A 2013-01-08 2013-01-11
7  A 2013-01-12 2013-01-15

预期结果:

代码语言:javascript
运行
复制
  ID      start        end
1  A 2013-01-01 2013-01-06
2  A 2013-01-07 2013-01-11
3  A 2013-01-12 2013-01-15

我试过的是:

代码语言:javascript
运行
复制
  require(dplyr)
  data <- structure(list(ID = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L), class = "factor", .Label = "A"), 
    start = structure(c(1356998400, 1356998400, 1357084800, 1357257600, 
    1357516800, 1357603200, 1357948800), tzone = "UTC", class = c("POSIXct", 
    "POSIXt")), end = structure(c(1357344000, 1357344000, 1357171200, 
    1357430400, 1357689600, 1357862400, 1358208000), tzone = "UTC", class = c("POSIXct", 
    "POSIXt"))), .Names = c("ID", "start", "end"), row.names = c(NA, 
-7L), class = "data.frame")

remove.overlaps <- function(data){
data2 <- data
for ( i in 1:length(unique(data$start))) {
x3 <- filter(data2, start>=data$start[i] & start<=data$end[i])
x4 <- x3[1,]
x4$end <- max(x3$end)
data2 <- filter(data2, start<data$start[i] | start>data$end[i])
data2 <- rbind(data2,x4)  
}
data2 <- na.omit(data2)}

data <- remove.overlaps(data)
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-03-09 09:31:16

这是一个可能的解决方案。这里的基本思想是使用start函数将滞后的cummax日期与最大结束日期“到目前为止”进行比较,并创建将数据分成组的索引。

代码语言:javascript
运行
复制
data %>%
  arrange(ID, start) %>% # as suggested by @Jonno in case the data is unsorted
  group_by(ID) %>%
  mutate(indx = c(0, cumsum(as.numeric(lead(start)) >
                     cummax(as.numeric(end)))[-n()])) %>%
  group_by(ID, indx) %>%
  summarise(start = first(start), end = last(end))

# Source: local data frame [3 x 4]
# Groups: ID
# 
#   ID indx      start        end
# 1  A    0 2013-01-01 2013-01-06
# 2  A    1 2013-01-07 2013-01-11
# 3  A    2 2013-01-12 2013-01-15
票数 21
EN

Stack Overflow用户

发布于 2017-11-16 19:32:37

@David的回答很棒--但我遇到了一个问题,即一个较早的间隔在一个较晚的间隔之后结束--但是在summarise调用中使用summarise会导致错误的结束日期。我建议把first(start)last(end)改成min(start)max(end)

代码语言:javascript
运行
复制
data %>%
  group_by(ID) %>%
  mutate(indx = c(0, cumsum(as.numeric(lead(start)) >
                     cummax(as.numeric(end)))[-n()])) %>%
  group_by(ID, indx) %>%
  summarise(start = min(start), end = max(end))

此外,正如@Jonno所提到的,在应用该方法之前,通过start和任何分组变量进行排序非常重要。

票数 14
EN

Stack Overflow用户

发布于 2017-11-20 10:53:04

为了完整起见,生物导体封装有一些简洁的函数,可以用来处理日期或日期的时间范围。其中一个是reduce()函数,它合并重叠或相邻的范围。

但是,有一个缺点,因为IRanges工作在整数范围(因此名),所以使用IRanges函数的方便是以牺牲DatePOSIXct对象之间的相互转换为代价的。

而且,似乎dplyrIRanges打得不好(至少从我在dplyr方面的有限经验来看),所以我使用了data.table

代码语言:javascript
运行
复制
library(data.table)
options(datatable.print.class = TRUE)
library(IRanges)
library(lubridate)

setDT(data)[, {
  ir <- reduce(IRanges(as.numeric(start), as.numeric(end)))
  .(start = as_datetime(start(ir)), end = as_datetime(end(ir)))
}, by = ID]

ID start end <fctr> <POSc> <POSc> 1: A 2013-01-01 2013-01-06 2: A 2013-01-07 2013-01-11 3: A 2013-01-12 2013-01-15

代码变体是

代码语言:javascript
运行
复制
setDT(data)[, as.data.table(reduce(IRanges(as.numeric(start), as.numeric(end))))[
  , lapply(.SD, as_datetime), .SDcols = -"width"], 
  by = ID]

在这两个变体中,都使用来自lubridate包的lubridate,这将在将数字转换为POSIXct对象时指定原点。

看到IRanges方法与大卫的回答之间的基准比较会很有趣。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28938147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档