为何plm对dplyr生成的数据框处理结果异常?
问题:dplyr处理pdata.frame后plm建模结果与base R处理不一致
我用base R和dplyr对同一个pdata.frame执行完全相同的筛选操作,之后用lm()建模结果完全一致,但传入plm()做固定效应(within方法)建模时,模型参数估计和面板结构识别都出现了明显差异。以下是可复现的代码(使用R 4.2.3、dplyr 1.1.1版本):
set.seed(1) library(dplyr) library(magrittr) library(plm) # 生成测试数据集 A = c(runif(100)) B = c(runif(100)) C = c(runif(100)) df <- data.frame(A,B,C) df$id <- floor((as.numeric(rownames(df))-1)/10) df$t <- ave(df$A, df$id, FUN = seq_along) # base R处理 df_base <- pdata.frame(df, index = c('id','t')) df_base <- subset(df_base, (as.numeric(df_base$t)<8)) # dplyr处理 df_dplyr <- pdata.frame(df, index = c('id','t')) df_dplyr <- df_dplyr %>% filter(as.numeric(t)<8) # lm建模结果一致 print(summary(lm(A ~ B + C, data = df_base))) print(summary(lm(A ~ B + C, data = df_dplyr))) # plm建模结果差异明显 print(summary(plm(A ~ B + C,data = df_base, method = "within"))) print(summary(plm(A ~ B + C,data = df_dplyr, method = "within")))
原因分析
核心问题是dplyr的filter()操作会丢失pdata.frame的面板属性:
- base R的
subset()函数会保留pdata.frame的索引(index)元数据,plm可以正确识别个体和时间维度 - dplyr处理后的
df_dplyr已经不再是pdata.frame,plm会自动尝试重新解析数据的面板结构,导致识别错误,最终影响固定效应的估计结果
可以用以下代码验证属性差异:
# 检查是否为pdata.frame is.pdata.frame(df_base) # 返回TRUE is.pdata.frame(df_dplyr) # 返回FALSE # 查看面板索引 index(df_base) # 正常输出id和t的索引信息 index(df_dplyr) # 报错,因为已丢失面板属性
解决方案
有两种简单的方法可以解决这个问题:
方案1:dplyr处理后重新转为pdata.frame
在filter操作后,手动将数据集重新转为pdata.frame并指定索引:
df_dplyr <- df_dplyr %>% filter(as.numeric(t)<8) %>% pdata.frame(index = c('id','t'))
方案2:使用plm包自带的psubset()函数
plm提供了专门用于pdata.frame的筛选函数psubset(),它会自动保留面板属性:
df_dplyr <- psubset(df_dplyr, as.numeric(t)<8)
修改后再运行plm建模代码,两个数据集的模型结果就会完全一致。
内容的提问来源于stack exchange,提问作者snowpeak
相关产品推荐
相关产品推荐

