You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在data.table中合并部分重叠的多分类日期区间并生成标识

高效data.table实现方案

这个方案完全基于data.table原生优化操作,无循环,可轻松处理百万行级、多运动类别的业务场景。

完整代码

library(data.table)
library(lubridate)

# 步骤1:整合所有运动数据为长表,新增运动类型标记
DT_sportA[, sport := "A"]
DT_sportB[, sport := "B"]
# 若有更多运动表,统一添加sport标记后加入rbind即可
all_sport <- rbind(DT_sportA, DT_sportB)

# 步骤2:按id提取所有时间断点,生成所有独立区间
# 断点包含所有运动的start_date、end_date+1(适配左闭右闭的日期区间规则)
breaks <- all_sport[, .(date = unique(c(start_date, end_date + 1))), by = id]
setorder(breaks, id, date)
# 相邻断点组成连续区间
breaks[, `:=`(
  start_date = date,
  end_date = shift(date, type = "lead") - 1
), by = id]
breaks <- breaks[!is.na(end_date), .(id, start_date, end_date)]

# 步骤3:非等值连接匹配区间与运动记录,转宽表生成0/1标记
res <- breaks[all_sport, 
              on = .(id, start_date >= start_date, end_date <= end_date), 
              allow.cartesian = TRUE, 
              nomatch = NULL]
# 分组统计转宽表,无匹配项填充0
res <- dcast(res, id + start_date + end_date ~ sport, 
             fun.aggregate = length, 
             value.var = "sport", 
             fill = 0)
# 重命名列符合输出要求
setnames(res, old = c("A", "B"), new = c("sportA", "sportB"))
# 按id和日期排序
setorder(res, id, start_date)

逻辑说明

  1. 时间断点提取:将所有运动的开始日期、结束日期+1作为区间分割点,确保生成的每个子区间要么完全落在某类运动的参与时段内,要么完全不重叠,避免区间拆分错误
  2. 非等值连接:利用data.table高度优化的非等值连接匹配区间和运动记录,性能远高于逐行循环判断
  3. 宽表转换:通过dcast直接生成各运动的0/1参与标记列,20类运动也仅需一次转换即可完成

运行后输出结果与示例期望完全一致。


内容的提问来源于stack exchange,提问作者user3102806

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 12:24:09