使用ggplot2绘制单变量持续时间时间序列数据的高效方案咨询
高效实现方案
你原来的逐天打标记的方案在日期跨度大、企业样本量高时会产生极高的内存占用,计算效率很低,这里提供两种更优的实现思路:
方法1:事件点增量累加(最高效,全场景通用)
核心逻辑:仅用事件的起止节点做增量统计,不需要生成逐行逐天的宽表,内存占用极低,计算速度不受日期跨度影响:
- 每条事件拆为两个节点:事件开始当天计数+1,事件结束次日计数-1(因为结束当天仍属于事件存续期)
- 按日期聚合所有增量后累加,即可得到每日存续企业数
对应的R实现代码:
library(tidyverse) library(lubridate) # 示例数据生成 set.seed(123) df <- data.frame(id = sample(100:500, 100, replace = F)) df$start <- sample(seq(as.Date('2020/01/01'), as.Date('2020/12/31'), by="day"), 100) df$end <- df$start + sample(1:50, replace = T) # 增量统计计算 daily_count <- df %>% # 拆分起止节点 pivot_longer(cols = c(start, end), names_to = "type", values_to = "date") %>% mutate(change = ifelse(type == "start", 1, -1), # 结束节点调整为次日 date = if_else(type == "end", date + days(1), date)) %>% # 按日期聚合增量 group_by(date) %>% summarise(change = sum(change)) %>% # 补全所有日期 complete(date = seq.Date(min(df$start), max(df$end), by = "day"), fill = list(change = 0)) %>% # 累加得到当日存续数 mutate(cnt = cumsum(change))
方法2:非等值连接统计(适合结构化查询场景)
如果用data.table的非等值连接语法,也可以快速完成范围统计,代码更简洁:
library(data.table) setDT(df) # 生成完整日期序列 date_dt <- data.table(date = seq(min(df$start), max(df$end), by = "day")) # 非等值连接统计每日符合条件的企业数 daily_count <- df[date_dt, on = .(start <= date, end >= date), .N, by = .EACHI] setnames(daily_count, c("date", "end", "cnt")) daily_count <- daily_count[, .(date, cnt)]
结果可视化
得到每日统计结果后直接绘图即可:
ggplot(daily_count, aes(x = date, y = cnt)) + geom_line(color = "#2c3e50") + labs(x = "日期", y = "存续事件企业数量") + theme_minimal()
内容的提问来源于stack exchange,提问作者Elizabeth Brown
相关产品推荐
相关产品推荐

