在R中计算含中断或重叠的日期区间总时长(车辆拥有年限统计)
计算存在重叠/中断的车辆拥有总年限(R实现)
需要统计每个人的车辆拥有总年限,核心规则:
- 同一时间段拥有多辆车时,重叠部分不重复计算
- 未拥有车辆的中断期,不计入总时长
示例数据
person <- c("Layla", "Layla", "Layla", "John", "John", "John", "Bo", "Bo") car <- c("Volvo x", "Volvo y", "Fiat Q", "Tesla C", "Mazda H", "Ford W", "Honda 1", "Honda 2") from_date <- as.Date(c("2000-01-01", "2009-01-02", "2011-01-05", "2000-08-01", "2004-07-09", "2008-01-01", "2001-01-01", "2003-07-01")) end_date <- as.Date(c("2010-01-01", "2012-07-01", "2015-08-09", "2002-01-01", "2020-10-22", "2010-01-01", "2020-08-09", "2019-10-01")) data <- data.frame(person, car, from_date, end_date)
数据结构预览:
person car from_date end_date 1 Layla Volvo x 2000-01-01 2010-01-01 2 Layla Volvo y 2009-01-02 2012-07-01 3 Layla Fiat Q 2011-01-05 2015-08-09 4 John Tesla C 2000-08-01 2002-01-01 5 John Mazda H 2004-07-09 2020-10-22 6 John Ford W 2008-01-01 2010-01-01 7 Bo Honda 1 2001-01-01 2020-08-09 8 Bo Honda 2 2003-07-01 2019-10-01
解决方案(兼容R 4.3.1)
使用dplyr和lubridate包处理,无需依赖不兼容的genomicranger:
library(dplyr) library(lubridate) result <- data %>% # 按用户分组 group_by(person) %>% # 按起始日期排序,方便合并区间 arrange(from_date, .by_group = TRUE) %>% # 标记当前区间是否与上一个区间重叠或连续 mutate( overlap = from_date <= lag(end_date, default = first(from_date) - 1), # 生成分组ID,用于合并区间 group_id = cumsum(!overlap) ) %>% # 按合并后的区间分组,计算每个合并区间的起止日期 group_by(person, group_id) %>% summarise( start = min(from_date), end = max(end_date), .groups = "drop_last" ) %>% # 计算每个用户的总年限,保留1位小数 summarise( carowner_yearsum = round(as.numeric(difftime(end, start, units = "days")) / 365.25, 1), .groups = "drop" ) print(result)
预期输出
# A tibble: 3 × 2 person carowner_yearsum <chr> <dbl> 1 Bo 19.5 2 John 8.0 3 Layla 15.0
代码逻辑说明
- 分组排序:按用户分组后,对每个用户的车辆区间按起始日期排序,确保后续合并顺序正确。
- 标记重叠区间:通过比较当前区间的起始日期与上一个区间的结束日期,判断是否重叠或连续,生成合并分组ID。
- 合并区间:按合并分组ID聚合,得到每个用户的非重叠连续区间的起止日期。
- 计算总时长:将每个合并区间的天数转换为年(按年平均365.25天计算),求和后保留1位小数。
内容的提问来源于stack exchange,提问作者Sofie Abildgaard
相关产品推荐
相关产品推荐

