大样本Propensity Score Matching(PMS)执行异常咨询:200万行数据用MatchIt包跑最近邻匹配耗时超一天未正常终止,求替代方法
哇,200万行数据跑MatchIt的最近邻匹配卡一天还没结束,太闹心了——我之前处理百万级样本的PSM时也踩过一模一样的坑,给你分享几个亲测有效的高效方案,从调参换包到预处理都有:
一、先从MatchIt本身优化(不用换包)
如果不想换工具,先试试这些参数调整,能大幅提速:
- 简化倾向得分模型:别给模型塞一堆高阶交互、多项式项,200万行数据下,复杂GLM的拟合本身就慢到离谱。可以先用
glmnet做LASSO变量筛选,只保留显著的主效应变量再代入MatchIt,比如:library(glmnet) x <- model.matrix(treat ~ ., data = dat)[, -1] y <- dat$treat lasso_fit <- cv.glmnet(x, y, family = "binomial") selected_vars <- coef(lasso_fit, s = "lambda.min") %>% rownames() %>% setdiff("(Intercept)") # 用筛选后的变量拟合MatchIt match_formula <- as.formula(paste("treat ~", paste(selected_vars, collapse = " + "))) m <- matchit(match_formula, data = dat, method = "nearest", replace = TRUE, ratio = 1) - 调整匹配核心参数:
- 设
replace = TRUE(允许对照被重复匹配),比无替换匹配的计算量小很多; - 用
ratio = 1(只匹配1个对照),别搞多匹配; - 对关键分类变量用
exact = ~group_var做精确匹配,提前缩小匹配池,比如先按性别、地区精确分组,再在组内做PSM。
- 设
- 开启并行计算:MatchIt 4.0+版本支持用
future包并行,把CPU核心全用上:library(future) plan(multisession, workers = parallel::detectCores() - 1) # 留一个核心给系统 m <- matchit(treat ~ x1 + x2, data = dat, method = "nearest", future = TRUE)
二、换用大样本友好的PSM工具包
如果MatchIt怎么调都慢,直接换这些专门优化过大样本的包:
Matching包:底层用C++实现,最近邻匹配的速度是MatchIt的数倍,还支持并行。建议先单独拟合倾向得分,再传入匹配:library(Matching) # 先拟合倾向得分 ps <- glm(treat ~ x1 + x2 + x3, data = dat, family = binomial)$fitted.values # 最近邻匹配,M=1是匹配1个对照,replace=TRUE允许重复匹配,parallel=TRUE开并行 match_result <- Match(Tr = dat$treat, X = ps, M = 1, replace = TRUE, parallel = TRUE) # 提取匹配后的样本 matched_dat <- rbind(dat[match_result$index.treated, ], dat[match_result$index.control, ])optmatch包:针对大样本的最优匹配和最近邻匹配做了线性规划优化,适合需要严格平衡 covariates 的场景:library(optmatch) ps <- glm(treat ~ x1 + x2, data = dat, family = binomial)$fitted.values # 最近邻匹配,max.controls=1限制每个处理组匹配1个对照 m <- fullmatch(treat ~ ps, data = dat, max.controls = 1) matched_dat <- dat[!is.na(m), ]- 手动用
fastmatch实现极速匹配:如果追求极致速度,自己写逻辑用fastmatch的哈希匹配,百万级样本秒级完成:library(fastmatch) # 按处理组和倾向得分排序 dat_sorted <- dat[order(dat$treat, dat$ps), ] # 拆分处理组和对照组的倾向得分 treat_ps <- dat_sorted$ps[dat_sorted$treat == 1] control_ps <- dat_sorted$ps[dat_sorted$treat == 0] # 快速匹配最近邻 match_indices <- fmatch(treat_ps, control_ps, nomatch = NA_integer_) # 提取匹配后的样本 matched_treat <- dat_sorted[dat_sorted$treat == 1, ] matched_control <- dat_sorted[dat_sorted$treat == 0 & seq_along(control_ps) %in% match_indices, ] matched_dat <- rbind(matched_treat, matched_control)
三、预处理数据,从根源减少计算量
- 先做粗匹配(CEM):用
cem包先对关键变量做粗分类匹配,把样本分成若干平衡的层,再在每层内做PSM,计算量直接砍半:library(cem) # 对连续变量设置分箱,比如x1分3箱,x2分4箱 mat <- cem(treatment = "treat", data = dat, cutpoints = list(x1 = c(0, 50, 100), x2 = 4)) # 提取粗匹配后的样本 cem_dat <- dat[mat$matched, ] # 再在cem_dat里跑PSM - 过滤极端倾向得分样本:把倾向得分在0.01~0.99之外的样本删掉,这些样本本来就很难匹配,去掉后匹配池变小,还能减少极端值对结果的干扰。
内容的提问来源于stack exchange,提问作者ymmy
相关产品推荐
相关产品推荐

