survey包中svyglm与svyolr权重不一致:Bug还是设计如此?
我的核心目标是在考虑抽样权重(使用survey包)的前提下,借助mediation R包开展中介分析。但过程中发现survey::svyglm与survey::svyolr拟合的模型权重存储方式存在差异,导致mediation::mediate函数执行失败,报错信息为:
'weights on outcome and mediator models not identical'
复现代码
set.seed(3459823) library(survey) library(srvyr) library(tidyverse) library(mediation) n <- 100 # simulate data dat <- tibble::tibble( id = 1:100, y_binary = sample(c(0,1), size = n, replace = TRUE), m_binary = sample(c(0,1), size = n, replace = TRUE), m_ordinal = sample(c(1, 2, 3), size = n, replace = TRUE, prob = c(0.2, 0.3, 0.5)) |> as.factor() |> as.ordered(), pred_normal = rnorm(n = n), weight = rnorm(n = n, mean = 15), weight_rep1 = rnorm(n = n, mean = weight), weight_rep2 = rnorm(n = n, mean = weight), weight_rep3 = rnorm(n = n, mean = weight), weight_rep4 = rnorm(n = n, mean = weight), weight_rep5 = rnorm(n = n, mean = weight) ) # create design object dat_design <- dat |> srvyr::as_survey_rep( repweights = dplyr::contains("_rep"), weights = weight, combined_weights = TRUE ) # ordinal mediator models model_y_binary <- survey::svyglm( formula = y_binary ~ m_ordinal + pred_normal, design = dat_design, family = "binomial" ) model_m_ordinal <- survey::svyolr( formula = m_ordinal ~ pred_normal, design = dat_design ) mediation_ordinal <- mediation::mediate( model.m = model_m_ordinal, model.y = model_y_binary, sims = 50, treat = "pred_normal", mediator = "m_ordinal" ) # Won't run! # Error in mediation::mediate(model.m = model_m_ordinal, model.y = model_y_binary, : # weights on outcome and mediator models not identical
权重差异检查
使用model.frame()函数(mediation::mediate提取权重的底层方法)检查模型权重,发现svyglm拟合的二项模型存储归一化后的权重,svyolr拟合的有序模型存储原始权重,二者样本权重比值均约为0.0673:
# Inspecting the weights saved by the survey models: model.frame(model_y_binary) |> dplyr::slice_head() # Result: # y_binary m_ordinal pred_normal (weights) # 1 1 3 -0.09479119 1.004946 # so, the binomial model stores the weights in a column in the model.frame model.frame(model_m_ordinal) |> dplyr::slice_head() # Result: # m_ordinal pred_normal (weights) # 1 3 -0.09479119 14.92443 # so, the ordinal model stores the weight as well, but they are different! weight_comparison <- tibble::tibble( binomial_weights = model.frame(model_y_binary)$`(weights`, ordinal_weights = model.frame(model_m_ordinal)$`(weights)`, weight_quotient = binomial_weights / ordinal_weights ) weight_comparison |> dplyr::slice_head(n = 5) # Result: # binomial_weights ordinal_weights weight_quotient # <dbl> <dbl> <dbl> # 1 1.00 14.9 0.0673 # 2 1.03 15.2 0.0673 # 3 0.992 14.7 0.0673 # 4 1.01 14.9 0.0673 # 5 0.927 13.8 0.0673 # so, all the binomial weights seem to be equal to the ordinal weights times ~0.0673
问题解答
1. 权重存储差异的原因是什么?
这是两个函数的拟合逻辑差异导致的:
svyglm基于广义线性模型框架,会自动将权重归一化到总和等于样本量,目的是让模型残差、拟合结果更易解释,同时避免权重绝对值过大引发的数值计算问题。svyolr是有序logistic回归的抽样加权实现,直接使用原始抽样权重拟合,没有加入自动归一化步骤——这是因为有序回归的比例优势模型算法在设计时,保留了原始权重的尺度逻辑。
本质上两种权重是成比例的,仅尺度不同,不会影响模型参数的相对估计结果,但会触发mediation包的权重一致性检查。
2. 是否可以修改已拟合的survey::svyolr模型对象,使其权重与svyglm模型一致?
可以,手动对svyolr的权重做归一化处理即可,代码示例如下:
# 计算缩放因子:svyglm权重总和为样本量,所以用样本量除以svyolr原始权重的总和 scale_factor <- nrow(model.frame(model_m_ordinal)) / sum(model.frame(model_m_ordinal)$`(weights)`) # 修改svyolr模型的model.frame中的权重 model_m_ordinal$model.frame$`(weights)` <- model_m_ordinal$model.frame$`(weights)` * scale_factor # 同步修改模型对象中存储的权重 model_m_ordinal$weights <- model_m_ordinal$weights * scale_factor
修改后重新运行mediation::mediate即可通过权重检查。这种修改只是缩放了权重尺度,不会改变模型参数的估计结果。
3. 是否可以调整mediation包适配该情况(例如仅使用中介模型权重,虽可能引发其他问题)?
有两种可行方式:
方式一:统一权重尺度后运行
直接按照问题2的方法,将两个模型的权重统一为同一尺度(归一化或原始权重),再调用mediate函数,这是最稳妥的方式。
方式二:绕过权重检查(不推荐,需谨慎)
如果不想修改模型,可以手动提取两个模型的参数,按照中介分析的逻辑自行计算效应(比如参数法或自助法),但这需要对中介分析的底层逻辑有一定了解。
另外,也可以尝试使用mediate函数的weights参数手动指定统一权重,但需要注意该参数对survey模型的兼容性。
需要注意:只要权重成比例,中介效应的估计结果是一致的,标准误可能因尺度变化有细微差异,但通常可忽略。
内容的提问来源于stack exchange,提问作者Vasco Brazao

