You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用R的MatchIt保留caliper内所有匹配单元(非仅近邻)?

带替换的全Caliper内倾向得分匹配实现方案

MatchIt直接实现的限制

MatchIt::matchit()的caliper参数默认绑定最近邻匹配逻辑,只会为每个处理单元挑选caliper范围内距离最近的控制单元,无法直接保留所有符合caliper条件的控制单元。不过可以通过手动结合倾向得分估计,或借助其他工具实现需求。

可行实现方案

方案1:手动实现全Caliper匹配(带替换)

核心思路是先估计倾向得分,再为每个处理单元筛选所有落在caliper范围内的控制单元,允许同一控制单元被多次匹配。

示例代码:

# 模拟示例数据
set.seed(123)
n_treat <- 100
n_control <- 500

# 生成处理组与控制组数据
treat_data <- data.frame(
  treat = 1,
  x1 = rnorm(n_treat, mean = 2),
  x2 = rbinom(n_treat, 1, 0.6)
)

control_data <- data.frame(
  treat = 0,
  x1 = rnorm(n_control, mean = 1.5),
  x2 = rbinom(n_control, 1, 0.4)
)

dat <- rbind(treat_data, control_data)

# 估计倾向得分
ps_model <- glm(treat ~ x1 + x2, data = dat, family = binomial)
dat$ps <- predict(ps_model, type = "response")

# 设置caliper(此处用处理组倾向得分标准差的0.2倍)
caliper_val <- 0.2 * sd(dat$ps[dat$treat == 1])

# 拆分处理单元与控制单元
treat_units <- subset(dat, treat == 1)
control_units <- subset(dat, treat == 0)

# 构建匹配结果
matched_list <- list()
for (i in seq(nrow(treat_units))) {
  current_ps <- treat_units$ps[i]
  # 筛选所有符合caliper条件的控制单元
  eligible_ctrl <- control_units[abs(control_units$ps - current_ps) <= caliper_val, ]
  
  if (nrow(eligible_ctrl) > 0) {
    matched_list[[i]] <- data.frame(
      treat_id = rownames(treat_units)[i],
      ctrl_id = rownames(eligible_ctrl),
      treat_ps = current_ps,
      ctrl_ps = eligible_ctrl$ps
    )
  }
}

# 合并匹配对并生成最终数据集
matched_pairs <- do.call(rbind, matched_list)
final_matched_data <- rbind(
  treat_units[matched_pairs$treat_id, ],
  control_units[matched_pairs$ctrl_id, ]
)

# 可选:为控制单元添加匹配权重(被匹配次数)
final_matched_data$weight <- 1
ctrl_weights <- table(matched_pairs$ctrl_id)
final_matched_data$weight[final_matched_data$treat == 0] <- 
  ctrl_weights[as.character(rownames(final_matched_data[final_matched_data$treat == 0, ]))]

方案2:使用Matching包实现批量匹配

如果不想手动循环,Matching包的Match()函数可以通过设置replace = TRUE开启带替换匹配,同时通过k参数指定每个处理单元匹配的最大数量。若将k设置为足够大的值(比如控制单元总数),就能匹配所有符合caliper条件的单元:

library(Matching)

# 估计倾向得分(同上)
ps_model <- glm(treat ~ x1 + x2, data = dat, family = binomial)
dat$ps <- predict(ps_model, type = "response")

# 执行带替换的全caliper匹配
match_result <- Match(
  Tr = dat$treat,
  X = dat$ps,
  replace = TRUE,
  caliper = caliper_val,
  k = nrow(control_units) # 设置为控制单元总数,匹配所有符合条件的单元
)

# 提取匹配数据集
matched_indices <- c(match_result$index.treated, match_result$index.control)
final_matched_data <- dat[matched_indices, ]

注意事项

  • Caliper的取值建议参考领域常规(比如0.1~0.2倍处理组倾向得分标准差),避免范围过大导致匹配质量下降
  • 带替换匹配会让部分控制单元被多次使用,后续分析时需要引入匹配权重(如方案1中计算的weight)来校正重复样本的影响

内容的提问来源于stack exchange,提问作者JRR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:45:27