Jon*_*rne 13 datetime r date lubridate
我有一个大的时间段数据集,由"开始"和"结束"列定义.有些时期重叠.
我想将所有重叠时间段组合(展平/合并/折叠)以具有一个"开始"值和一个"结束"值.
一些示例数据:
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
Run Code Online (Sandbox Code Playgroud)
期望的结果:
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
Run Code Online (Sandbox Code Playgroud)
我尝试过的:
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)
Run Code Online (Sandbox Code Playgroud)
Dav*_*urg 16
这是一个可能的解决方案.这里的基本思想是start使用cummax函数将滞后日期与"直到现在"的最大结束日期进行比较,并创建一个将数据分组的索引
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
Run Code Online (Sandbox Code Playgroud)
zac*_*ack 11
@David Arenburg的答案很棒 - 但是我遇到了一个问题,即较早的间隔在稍后的间隔后结束 - 但是last在summarise通话中使用会导致错误的结束日期.我建议改变first(start)并last(end)以min(start)与max(end)
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))
Run Code Online (Sandbox Code Playgroud)
另外,正如@Jonno Bourne所提到的,start在应用该方法之前,排序依据和任何分组变量都很重要.
为了完整起见,Bioconductor上的IRanges包具有一些简洁的功能,可用于处理日期或日期时间范围。其中之一是reduce()合并重叠或相邻范围的功能。
但是,有一个缺点,因为它IRanges适用于整数范围(因此得名),因此使用IRanges函数的便利性是以来回转换Date或POSIXct对象为代价的。
此外,它似乎dplyr不太适合IRanges(至少根据我有限的经验判断dplyr)所以我使用data.table:
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]
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)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
代码变体是
setDT(data)[, as.data.table(reduce(IRanges(as.numeric(start), as.numeric(end))))[
, lapply(.SD, as_datetime), .SDcols = -"width"],
by = ID]
Run Code Online (Sandbox Code Playgroud)
在这两种变体中as_datetime(),lubridate都使用了from包,在将数字转换为POSIXct对象时,它可以用来指定原点。
看到这些IRanges方法与大卫的答案的基准比较会很有趣。