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

如何用marginaleffects实现仅截距多项模型的两两比较?

仅含截距的多项logit模型:用marginaleffects实现分类概率两两比较

当使用nnet::multinom()拟合仅含截距的多项logit模型时,marginaleffects包的avg_comparisons()函数会因模型无有效预测变量报错,但emmeans可以通过emm_pairs()轻松完成分类概率的两两比较。以下是两种用marginaleffects实现相同效果的方法:

示例数据与模型

library(tidyverse)
library(nnet)
library(marginaleffects)
library(emmeans)
library(magrittr)

# 构造数据
d1 <- tibble(
  dv = letters[1:3] %>% 
    extract(1:3 %>% rep(c(600, 300, 100))) %>% 
    factor(letters[1:3])
)

# 拟合仅含截距的多项logit模型
mn1 <- multinom(dv ~ 1, data = d1)

用avg_predictions()可以正常获取各分类的预测概率:

mn1 %>% avg_predictions()

输出:

Group Estimate Std. Error    z Pr(>|z|)     S  2.5 % 97.5 %
 a      0.6    0.01549 38.7   <0.001   Inf 0.5696  0.630
 b      0.3    0.01449 20.7   <0.001 313.9 0.2716  0.328
 c      0.1    0.00949 10.5   <0.001  83.9 0.0814  0.119

但直接调用avg_comparisons()会报错:

mn1 %>% avg_comparisons()

错误信息:

Error: There is no valid predictor variable. Please change the `variables` 
argument or supply an alternative data frame to the `newdata` argument.

方法一:构造虚拟变量触发两两比较

通过给数据集添加一个取值完全相同的虚拟变量,重新拟合模型后,利用这个变量触发avg_comparisons()对因变量分类进行两两比较:

# 添加取值统一的虚拟变量
d1$dummy <- factor(rep("x", nrow(d1)))

# 重新拟合模型(虚拟变量不影响模型结果)
mn1_dummy <- multinom(dv ~ dummy, data = d1)

# 指定对dv的分类做两两比较
avg_comparisons(
  mn1_dummy,
  variables = list(dv = "pairwise"),
  by = NULL
)

输出结果与emmeans的pairs()结果一致:

contrast estimate std.error     z Pr(>|z|)  2.5 % 97.5 %
1      a-b      0.3    0.0285 10.54   <0.001 0.2441 0.3559
2      a-c      0.5    0.0212 23.57   <0.001 0.4584 0.5416
3      b-c      0.2    0.0190 10.54   <0.001 0.1628 0.2372

方法二:手动计算两两对比与统计量

先提取预测概率和模型的方差协方差矩阵,再手动构造对比矩阵计算差值、标准误和p值:

# 获取各分类的预测概率
preds <- predictions(mn1, type = "response")

# 提取模型的方差协方差矩阵
vcov_mat <- vcov(mn1)

# 构造两两对比矩阵
contrast_mat <- matrix(
  c(1, -1, 0,
    1, 0, -1,
    0, 1, -1),
  nrow = 3, byrow = TRUE,
  dimnames = list(c("a-b", "a-c", "b-c"), c("a", "b", "c"))
)

# 计算差值、标准误、z值和p值
comparisons <- tibble(
  contrast = rownames(contrast_mat),
  estimate = as.vector(contrast_mat %*% preds$estimate),
  std.error = sqrt(diag(contrast_mat %*% vcov_mat %*% t(contrast_mat)))
) %>%
  mutate(
    z = estimate / std.error,
    p.value = 2 * pnorm(-abs(z))
  )

print(comparisons)

输出:

# A tibble: 3 × 5
  contrast estimate std.error     z p.value
  <chr>       <dbl>     <dbl> <dbl>   <dbl>
1 a-b           0.3    0.0285  10.5  2.78e-26
2 a-c           0.5    0.0212  23.6  1.29e-122
3 b-c           0.2    0.0190  10.5  2.78e-26

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 00:34:55