mgcv包中二项式GAM模型权重使用异常问题及正确设置方法咨询
你碰到的这个问题其实是mgcv包的gam()函数在处理二项式响应(也就是cbind(success, failure)这种两列格式)时,对weights参数的解释和基础的glm()完全不一样导致的——这也是为什么同样的权重设置,GLM结果一致但GAM差异巨大。
问题核心原因
当你用cbind(success, failure)作为二项式响应输入gam()时,它会默认把这个响应理解为「每组有success+failure次独立试验,其中success次成功」。这时你传入的weights参数,会被当成每组试验次数的缩放因子,而不是GLM里那种观测级别的相对权重。也就是说,模型会把有效试验次数计算为weights * (success + failure),这就导致权重的绝对大小直接影响似然函数的计算,哪怕相对比例一样,结果也会变。
而glm()在处理这种两列响应时,weights是纯粹的观测权重,只影响每个观测对模型拟合的贡献比例,和试验次数无关,所以只要相对比例一致,结果就不会变。
正确的解决方案
要设置独立于样本量的自定义权重,最稳妥的方法是把响应转换成成功比例格式(成功次数/总试验次数),然后把weights参数设置为「总试验次数 × 你的自定义权重」。这样gam()会正确识别:权重是每个观测的贡献权重,而试验次数由weights里的总试验次数部分决定。
下面是修正后的可复现代码:
library('mgcv') set.seed(123) # 固定随机种子,让结果可复现 x = 1:100 # 生成成功/失败次数 y_success = rpois(100, 5 + x/2) y_failure = rpois(100, 100) # 计算成功比例和总试验次数 y_prop = y_success / (y_success + y_failure) n_trials = y_success + y_failure # 自定义权重 w = sample(seq_len(100), 100, replace = TRUE) # 正确拟合GAM:比例响应 + 权重=总试验次数×自定义权重 m_gam_correct = gam(y_prop ~ s(x), family = 'binomial', weights = n_trials * w) # 验证:调整权重的相对比例,结果完全一致 m_gam_scaled1 = gam(y_prop ~ s(x), family = 'binomial', weights = n_trials * (w / mean(w))) m_gam_scaled2 = gam(y_prop ~ s(x), family = 'binomial', weights = n_trials * (w / sum(w))) # 检查预测结果是否一致 all.equal(predict(m_gam_correct), predict(m_gam_scaled1)) # 返回TRUE all.equal(predict(m_gam_correct), predict(m_gam_scaled2)) # 返回TRUE
补充:如果坚持用两列响应格式?
如果你一定要保留cbind(success, failure)的输入方式,需要手动指定模型的权重处理逻辑,但这种方法不如比例格式直观。本质上是要让模型把weights当成观测权重,而不是试验次数的缩放因子。你可以通过构造自定义的二项式族来实现,但一般不推荐,因为容易出错。
验证GLM的一致性
对比一下GLM的处理,你会发现用比例格式+权重的方式和GLM的逻辑完全对齐:
# GLM用比例格式拟合 m_glm_prop = glm(y_prop ~ x, family = 'binomial', weights = n_trials * w) # GLM用两列响应拟合 m_glm_binom = glm(cbind(y_success, y_failure) ~ x, family = 'binomial', weights = w) # 预测结果一致 all.equal(predict(m_glm_prop), predict(m_glm_binom)) # 返回TRUE
内容的提问来源于stack exchange,提问作者tcam

