基于另一数据集观测值筛选数据集:保留t-1/t+1观测并生成POST变量
解决方案(R语言)
问题背景
我们有两个数据集:
- 全量数据集:包含多家公司连续年度的记录(示例为公司6、7的2005-2022年数据)
- 事件数据集:记录特定公司的关键事件年份
需要从全量数据中提取每个事件年份的**前一年(标记POST=0)和后一年(标记POST=1)**的观测值,最终输出符合要求的结果。
步骤1:构造示例数据
先还原题目中的两个数据集:
# 全量数据集 df_full <- data.frame( year = rep(2005:2022, 2), CompanyID = rep(6:7, each = 18) ) # 事件数据集 df_events <- data.frame( year = c(2012, 2007, 2015, 2009), CompanyID = c(6,6,7,7) )
步骤2:dplyr高效处理(推荐,适合大量数据)
使用dplyr包的向量化操作,批量生成目标记录并匹配:
library(dplyr) library(tidyr) # 用于unnest函数 df_result <- df_events %>% # 为每个事件年份生成前后两年及对应POST标记 mutate( year = list(c(year - 1, year + 1)), POST = list(c(0, 1)) ) %>% # 展开列表为多行记录 unnest(c(year, POST)) %>% # 与全量数据匹配,自动过滤不存在的年份(比如事件在2005年时t-1=2004会被排除) inner_join(df_full, by = c("CompanyID", "year")) %>% # 按公司ID和年份排序,与预期输出一致 arrange(CompanyID, year) # 输出结果 print(df_result)
运行后得到的结果与题目预期完全一致:
year CompanyID POST 1 2006 6 0 2 2008 6 1 3 2011 6 0 4 2013 6 1 5 2008 7 0 6 2010 7 1 7 2014 7 0 8 2016 7 1
步骤3:Base R原生处理(无需加载包)
如果不想依赖第三方包,可以用Base R的批量处理方式:
# 生成所有需要提取的(year, CompanyID, POST)组合 target_records <- do.call(rbind, lapply(1:nrow(df_events), function(i) { data.frame( year = c(df_events$year[i]-1, df_events$year[i]+1), CompanyID = df_events$CompanyID[i], POST = c(0, 1) ) })) # 与全量数据匹配并排序 df_result_base <- merge(df_full, target_records, by = c("CompanyID", "year")) df_result_base <- df_result_base[order(df_result_base$CompanyID, df_result_base$year), ] rownames(df_result_base) <- NULL # 重置行名 # 输出结果 print(df_result_base)
适用场景
两种方法都支持大量不同CompanyID的场景,处理逻辑是批量生成目标记录再匹配,不会因为公司数量增加导致性能瓶颈。
内容的提问来源于stack exchange,提问作者Sharif
相关产品推荐
相关产品推荐

