基于data.table计算企业年度技术专利类别放弃数(3/5年窗口)
问题描述
需要在包含企业与专利类别的数据库中计算「技术放弃数(Technological abandonment)」变量:
- 定义:企业每年放弃的原活跃技术专利类别数量
- 计算规则:
- 统计企业过去N年窗口(如3年窗口为t-3、t-2、t-1;若企业历史不足N年,则统计所有已有历史年份)中使用过,但本年(t)未使用的专利类别数量
- 需同时支持3年、5年两种窗口计算
- 约束:数据集规模达数百万行,优先采用高效的
data.table方案
示例数据集
library(data.table) df <- data.table( year = c(1979,1979,1980,1980,1981,1981,1982,1983,1983,1984,1984), category = c("A","A","B","C","A","D","F","F","C","A","B") )
注:示例中省略了企业ID字段,实际场景需按企业分组计算
3年窗口预期输出
year category tech_aband_3 1: 1979 A 0 2: 1979 A 0 3: 1980 B 1 4: 1980 C 1 5: 1981 A 2 6: 1981 D 2 7: 1982 F 4 8: 1983 F 3 9: 1983 C 3 10: 1984 A 3 11: 1984 B 3
高效data.table实现方案
核心思路:先提取每个企业每年的唯一活跃专利类别,再通过滚动窗口统计历史活跃类别集合,最后对比本年类别计算放弃数量,全程用data.table的向量化操作保证效率。
步骤1:数据预处理(去重)
同一企业同一年可能有多条同一类别的记录,先去重得到「企业-年份-唯一类别」的精简数据集:
# 实际场景需加入企业ID(如firm_id)作为分组键 unique_df <- unique(df, by = c("year", "category"))
步骤2:定义通用窗口计算函数
封装函数支持任意N年窗口计算,复用性更强:
calc_tech_abandon <- function(dt, window_size = 3) { # 按年份排序,保证窗口逻辑正确 setorder(dt, year) # 1. 计算每个年份的历史窗口范围:最小年份到t-1,且不超过窗口上限 dt[, `:=`( window_start = pmax(min(year), year - window_size), window_end = year - 1 ), by = .(category)] # 实际场景替换为by = .(firm_id) # 2. 用非等值join匹配窗口内所有历史活跃类别 historical_classes <- dt[dt, on = .(year >= window_start, year <= window_end), allow.cartesian = TRUE, .(current_year = i.year, hist_category = x.category)] # 3. 按当前年份聚合,得到去重后的历史类别集合 hist_summary <- historical_classes[, .(hist_classes = list(unique(hist_category))), by = current_year] # 4. 统计本年的活跃类别集合 current_summary <- dt[, .(current_classes = list(unique(category))), by = year] # 5. 计算放弃数量:历史类别总数 - 历史与本年的交集数量 combined <- merge(current_summary, hist_summary, by.x = "year", by.y = "current_year", all.x = TRUE) combined[, `:=`( hist_count = sapply(hist_classes, length), intersect_count = mapply(function(h, c) length(intersect(h, c)), hist_classes, current_classes) )] combined[, tech_aband := hist_count - intersect_count] # 处理初始年份(无历史数据时放弃数为0) combined[is.na(tech_aband), tech_aband := 0] # 6. 合并回原数据集,补全重复行的计算结果 result <- merge(df, combined[, .(year, tech_aband)], by = "year", all.x = TRUE) setnames(result, "tech_aband", paste0("tech_aband_", window_size)) return(result) }
步骤3:执行计算
# 计算3年窗口结果 result_3 <- calc_tech_abandon(df, window_size = 3) # 计算5年窗口结果 result_5 <- calc_tech_abandon(df, window_size = 5) # 合并两个窗口的结果(可选) final_result <- merge(result_3, result_5, by = c("year", "category"))
性能优化说明
- 提前用
unique()去重,大幅减少后续计算的数据量 - 用非等值join替代循环遍历,利用
data.table的高效索引加速匹配 - 用列表存储类别集合,避免重复计算去重逻辑
- 全程采用向量化操作,适配百万级甚至更大规模的数据集
内容的提问来源于stack exchange,提问作者lovestacksflow
相关产品推荐
相关产品推荐

