You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在不修改原逻辑回归模型的前提下,如何在R中合并预测概率图中的指定线条?

在不修改原逻辑回归模型的前提下,如何在R中合并预测概率图中的指定线条?

这个问题太常见了——建模时要保留完整的变量交互关系保证统计严谨性,但绘图时为了简洁又需要合并部分组,完全不用动模型,只需要在预测结果的后处理环节做聚合就行!我给你一步步拆解解决方案:

核心思路

模型该怎么跑还是怎么跑,我们要做的是:

  1. 用原模型生成所有education_num(1-16)的预测概率
  2. education_num<=5的组,按age分组计算平均预测概率(代表这5组的整体趋势)
  3. 把聚合后的组和剩下的11个单独组合并,再用ggplot绘图

这种方法完全不碰原模型,只是在可视化环节做了数据整合,既满足统计严谨性,又实现了绘图简洁性。


完整代码(替换你原有的plot部分即可)

我直接基于你现有的代码修改,重点看############### 改进的绘图部分 ###############之后的内容:

# Load libraries
library(dplyr)
library(ggplot2)
library(sjPlot)
library(RColorBrewer)
library(splines)

# Load dataset
url <- "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"
column_names <- c(
  "age", "workclass", "fnlwgt", "education", "education_num",
  "marital_status", "occupation", "relationship", "race", "sex",
  "capital_gain", "capital_loss", "hours_per_week", "native_country", "income"
)
d <- read.table(url, sep = ",", header = FALSE, col.names = column_names, strip.white = TRUE)

# Prepare data
d <- d %>% mutate(
  age = as.numeric(age),
  education_num = as.numeric(education_num),
  income = factor(income, levels = c("<=50K", ">50K"))
)

############### 原模型完全保留,一点不动 ###############
inter <- glm(income ~ splines::ns(age, df = 4) * education_num, data = d, family = 'binomial')
summary(inter)

############### 改进的绘图部分 ###############
# 1. 生成预测用的网格数据:覆盖age的全范围 + 所有education_num值
pred_grid <- expand.grid(
  age = seq(min(d$age), max(d$age), length.out = 100),  # 生成100个平滑的age点
  education_num = unique(d$education_num)  # 包含1-16所有教育水平
)

# 2. 用原模型预测得到响应概率(type="response"得到0-1的概率)
pred_grid$pred_prob <- predict(inter, newdata = pred_grid, type = "response")

# 3. 聚合处理:把education_num<=5的组按age取平均
aggregated_pred <- pred_grid %>%
  mutate(
    # 给合并组标记特殊名称,其他组保留原教育水平
    ed_group = ifelse(education_num <= 5, "1-5 (平均)", as.character(education_num))
  ) %>%
  group_by(age, ed_group) %>%
  summarize(
    mean_pred = mean(pred_prob),  # 按age和组计算平均预测概率
    .groups = "drop"  # 取消分组,变回普通数据框
  )

# 4. 用ggplot绘制最终结果
ggplot(aggregated_pred, aes(x = age, y = mean_pred, color = ed_group)) +
  geom_line(linewidth = 1) +
  # 自定义颜色:合并组用显眼的黑色,其他组用Spectral调色板
  scale_color_manual(
    values = c(
      "1-5 (平均)" = "black",
      setNames(RColorBrewer::brewer.pal(11, "Spectral"), as.character(6:16))
    ),
    name = "教育水平(education_num)"
  ) +
  labs(
    x = "年龄",
    y = "年收入>50K的预测概率",
    title = "不同教育水平下,年龄对高收入概率的影响"
  ) +
  theme_minimal() +
  theme(legend.position = "right")

关键细节解释

  1. 为什么不用直接把education_num<=5设为5?
    你之前的顾虑完全正确——那样得到的是education_num=5单独的预测结果,不是1-5组的平均趋势,会有偏差。我们的方法是先算出1-5每个组的预测值,再按age取平均,能真实代表这一组的整体趋势。

  2. 为什么自己生成预测网格?
    sjPlot::plot_model虽然方便,但自定义聚合的灵活性不够。手动生成预测网格可以完全控制预测的点和变量组合,后续聚合处理更自由。

  3. 可以调整的细节

    • 聚合统计量:如果不想用平均,也可以换成median(pred_prob)(中位数),根据你的需求修改summarize里的函数即可
    • 平滑度:seq(min(d$age), max(d$age), length.out = 100)中的100可以调整,数值越大线条越平滑
    • 颜色和样式:可以修改scale_color_manual里的颜色,或者给合并组加linetype = "dashed"来进一步区分

这样处理后,你既能保留原模型的完整性,又能得到简洁易读的可视化结果😉

火山引擎 最新活动