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

在R语言中按日期区间统计匹配项的实现方法

问题描述

现有两个数据框:

  • DF_1:包含ID、TYPE、DT_START(区间起始日期)和DT_END(区间结束日期),其中ID+TYPE组合唯一
  • DF_2:包含ID、TYPE、DT(单个日期)

需按ID和TYPE匹配,统计DF_2中DT落在DF_1对应行DT_START与DT_END区间内的次数,最终生成带COUNT列的DF_3。


示例数据

DF_1 定义代码

ID <- c(111,222,222,333,444,444)
TYPE <- c('A1','A1','B1','B1','A1','B1')
DT_START <- as.Date(c('2022/07/20','2022/07/18','2022/07/10','2022/07/05','2022/07/03','2022/07/01'), "%Y/%m/%d")
DT_END <- as.Date(c('2021/07/20','2021/07/18','2021/07/10','2021/07/05','2021/07/03','2021/07/01'), "%Y/%m/%d")
DF_1 <- data.frame(ID,TYPE,DT_START,DT_END)

DF_2 定义代码

ID <- c(111,111,111,111,222,222,444,444,444)
TYPE <- c('A1','A1','A1','A1','A1','A1','A1','B1','B1')
DT <- as.Date(c('2022/06/01','2022/05/15','2022/01/01','2021/06/01','2022/03/02','2021/12/21','2021/12/29','2022/06/30','2022/06/15'), "%Y/%m/%d")
DF_2 <- data.frame(ID,TYPE,DT)

目标结果DF_3

ID <- c(111,222,222,333,444,444)
TYPE <- c('A1','A1','B1','B1','A1','B1')
DT_START <- as.Date(c('2022/07/20','2022/07/18','2022/07/10','2022/07/05','2022/07/03','2022/07/01'), "%Y/%m/%d")
DT_END <- as.Date(c('2021/07/20','2021/07/18','2021/07/10','2021/07/05','2021/07/03','2021/07/01'), "%Y/%m/%d")
COUNT <- c(3,2,0,0,1,2)
DF_3 <- data.frame(ID,TYPE,DT_START,DT_END,COUNT)

实现方法

方法1:dplyr(tidyverse)实现

通过关联、区间判断、分组统计三步完成,代码简洁易读:

library(dplyr)

DF_3 <- DF_1 %>%
  left_join(DF_2, by = c("ID", "TYPE")) %>%
  # 注意示例中DT_START晚于DT_END,所以区间判断顺序为DT_END在前
  mutate(in_range = between(DT, DT_END, DT_START)) %>%
  group_by(ID, TYPE, DT_START, DT_END) %>%
  summarise(COUNT = sum(in_range, na.rm = TRUE), .groups = "drop")

若实际数据中DT_START早于DT_END,将between参数改为between(DT, DT_START, DT_END)即可。

方法2:data.table实现

适合大数据量场景,运算效率更高:

library(data.table)

setDT(DF_1)
setDT(DF_2)

DF_3 <- DF_1[DF_2, on = .(ID, TYPE), allow.cartesian = TRUE][
  , .(COUNT = sum(between(DT, DT_END, DT_START), na.rm = TRUE)), 
  by = .(ID, TYPE, DT_START, DT_END)
]

方法3:基础R实现

无需额外依赖包,适合小数据量快速验证:

DF_3 <- DF_1
DF_3$COUNT <- apply(DF_3, 1, function(row) {
  # 筛选同ID同TYPE的DF_2记录
  target_rows <- DF_2[DF_2$ID == row["ID"] & DF_2$TYPE == row["TYPE"], ]
  # 统计符合区间条件的次数
  sum(target_rows$DT >= as.Date(row["DT_END"]) & target_rows$DT <= as.Date(row["DT_START"]), na.rm = TRUE)
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 17:51:22