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

R中调查加权多重插补数据如何计算合并平均边际效应

问题背景

当前处理带抽样权重的调查数据,已通过mice()完成缺失值多重插补,后续需要拟合含复杂交互项的模型,计算模型的平均边际效应(AME)。
该操作在Stata中流程简便,但需要在R环境完成分析。已知可以对每个单独插补数据集分别计算AME后对估计值取平均,但要得到正确标准误,必须调用mice包的pool()函数完成结果合并。

可复现问题的示例代码

library(tidyverse)
library(survey)
library(mice)
library(margins)

df <- tibble(y = c(0, 5, 0, 4, 0, 1, 2, 3, 1, 12), region = c(1, 1, 1, 1, 1, 3, 3, 3, 3, 3), 
             weight = c(7213, 2142, 1331, 4342, 9843, 1231, 1235, 2131, 7548, 2348), 
             x1 = c(1.14, 2.42, -0.34, 0.12, -0.9, -1.2, 0.67, 1.24, 0.25, -0.3),
             x2 = c(12, NA, 10, NA, NA, 12, 11, 8, 9, 9))

已验证可正常运行的场景

  • 对单一非多重插补数据拟合的svyglm对象调用margins()可正常运行
  • 通过with()基于每个插补数据集拟合svyglm后,用pool()合并回归结果可正常执行,对应代码:
m <- with(surv_obj, svyglm(y ~ x1 * x2))
pool(m)

报错/警告场景

  1. 在with()中嵌套调用margins(),返回错误:Error in .svycheck(design) : argument "design" is missing, with no default,对应代码:
with(surv_obj, margins(svyglm(y ~ x1 * x2), design = surv_obj))
  1. 在svyglm调用中显式指定design参数,返回错误:Error in UseMethod("svyglm", design) : no applicable method for 'svyglm' applied to an object of class "svyimputationList",对应代码:
with(surv_obj, margins(svyglm(y ~ x1 * x2, design = surv_obj), design = surv_obj))
  1. 移除调查设计层,直接对每个插补数据集拟合lm模型、调用margins()计算边际效应后用pool()合并,出现警告:Warning in get.dfcom(object, dfcom) : Infinite sample size assumed.,对应代码:
m1 <- with(imputed_df, margins(lm(y ~ x1 * x2)))
pool(m1)

pool()计算过程需要调用样本量参数,该警告会导致结果可靠性存疑。


可行方案

方案a:组合函数实现AME自动合并

with()处理多重插补对象时,会在每个插补子集的独立环境中运行表达式,全局环境中的调查设计对象无法被正确识别,因此嵌套调用会报错。正确流程为逐个处理每个插补数据集,将结果整理为mice支持的mira类对象后传入pool()即可。
完整可运行代码:

# 完成多重插补,可自行调整插补次数
imp <- mice(df, m = 5, printFlag = F)
# 构建多重插补调查设计对象
surv_obj <- svydesign(ids = ~1, weights = ~weight, data = imp)

# 逐个处理每个插补数据集
ame_list <- lapply(1:imp$m, function(i) {
  imp_data <- complete(imp, i)
  design_i <- svydesign(ids = ~1, weights = ~weight, data = imp_data)
  fit_i <- svyglm(y ~ x1 * x2, design = design_i)
  ame_i <- margins(fit_i, design = design_i)
  list(model = fit_i, ame = summary(ame_i))
})

# 整理为pool可识别的mira类结构
ame_mira <- list(
  call = call("margins"),
  nmis = imp$nmis,
  analyses = lapply(ame_list, function(x) {
    res <- list(
      coefficients = setNames(x$ame$AME, x$ame$factor),
      vcov = vcov(x$ame),
      df.residual = df.residual(x$model),
      call = x$model$call,
      terms = x$model$terms
    )
    class(res) <- c("svyglm", "glm", "lm")
    res
  }),
  m = imp$m
)
class(ame_mira) <- "mira"

# 合并结果,无无限样本量警告
pooled_ame <- pool(ame_mira)
summary(pooled_ame)

方案b:手动提取要素合并结果

如果不构造适配pool()的对象结构,可直接提取margins()输出的核心统计量,传入pool.scalar()按Rubin规则合并。需要提取的要素仅两类:

  • 每个边际效应在各插补数据集的点估计值
  • 每个边际效应在各插补数据集的抽样方差(即标准误的平方)

手动合并代码如下:

# 提取各插补集的AME估计值和方差
ame_est <- lapply(ame_list, function(x) setNames(x$ame$AME, x$ame$factor))
ame_var <- lapply(ame_list, function(x) {
  ses <- x$ame$SE
  setNames(ses^2, x$ame$factor)
})

# 逐变量调用pool.scalar合并
var_names <- names(ame_est[[1]])
pooled_res <- lapply(var_names, function(v) {
  q <- sapply(ame_est, function(x) x[v])
  u <- sapply(ame_var, function(x) x[v])
  ps <- pool.scalar(Q = q, U = u, n = nrow(df))
  data.frame(
    term = v,
    estimate = ps$qbar,
    std.error = sqrt(ps$t),
    statistic = ps$qbar / sqrt(ps$t),
    p.value = 2 * pnorm(abs(ps$qbar / sqrt(ps$t)), lower.tail = F),
    df = ps$df
  )
})
pooled_res <- do.call(rbind, pooled_res)

两种方法得到的结果完全一致,传入样本量参数后不会再触发无限样本量警告,标准误计算完全符合多重插补Rubin合并规则,同时正确纳入了调查权重的影响。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:36:27