如何用R筛选面板数据中含cutoff date前后观测值的企业?
筛选跨2017年临界点的企业面板数据解决方案
需求与数据说明
我们需要从企业面板数据中筛选出同时满足两个条件的企业:
- 至少有一条观测记录在2017年之前
- 至少有一条观测记录在2017年及之后
示例数据
df <- data.frame(year = rep(c(2010,2012,2017, 2010,2012,2017, 2008,2009,2018, 2017,2008,2009, 2017,2008,2009, 2005,2004,2002, 2003,2004,2008, 2020)), company = rep(c("A", "A", "A", "B", "B", "C", "C", "D", "D", "E", "E", "F", "G", "G", "G", "H", "H", "I", "J", "K", "K", "K")))
数据预览:
year company 2010 A 2012 A 2017 A 2010 B 2012 B 2017 C 2008 C 2009 D 2018 D 2017 E 2008 E 2009 F 2017 G 2008 G 2009 G 2005 H 2004 H 2002 I 2003 J 2004 K 2008 K 2020 K
预期结果
最终应筛选出的企业:A、C、D、E、G、K
原代码问题分析
你尝试的代码无法得到正确结果,问题出在没有按企业分组判断:
原代码逐行标记pre和post,但单一行的年份不可能同时小于2017和大于2017,自然筛选不到任何数据。即使加了group_by,如果没有用分组级别的判断逻辑,依然无法解决问题。
原代码:
df <- df %>% mutate(pre = case_when(year < 2017 ~ 1), post = case_when(year > 2017 ~ 1)) %>% mutate(both = pre + post) %>% filter(both == 2)
优雅解决方案
方法1:dplyr分组筛选(推荐)
通过group_by(company)按企业分组,用any()判断该企业是否存在符合条件的观测,最后保留满足双条件的企业所有记录:
library(dplyr) # 获取筛选后的完整数据集 result_df <- df %>% group_by(company) %>% filter(any(year < 2017) & any(year >= 2017)) %>% ungroup() # 如果只需要符合条件的企业名称列表 target_companies <- df %>% group_by(company) %>% filter(any(year < 2017) & any(year >= 2017)) %>% distinct(company) %>% pull(company)
方法2:base R原生实现
无需加载第三方包,通过聚合年份范围来判断:
# 计算每个企业的最小和最大年份 company_year_stats <- aggregate(year ~ company, df, function(x) c(min = min(x), max = max(x))) # 筛选符合条件的企业 target_companies <- company_year_stats$company[ company_year_stats$year[, "min"] < 2017 & company_year_stats$year[, "max"] >= 2017 ] # 获取对应数据 result_df <- df[df$company %in% target_companies, ]
方法3:data.table高效处理(适合大数据)
如果数据集规模较大,data.table的分组操作效率显著更高:
library(data.table) setDT(df) result_df <- df[, if(any(year < 2017) & any(year >= 2017)) .SD, by = company]
内容的提问来源于stack exchange,提问作者Joost Maxen
相关产品推荐
相关产品推荐

