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

R语言GAM模型基于type='terms'预测结果绘制平滑函数

GAM手动绘制平滑项实现方法

报错核心原因

之前的绘图代码报错是因为predict(..., type='terms')返回的preds是包含拟合值矩阵、标准误矩阵的列表,不能直接作为ggplot的y轴映射变量;且返回的平滑项数值是中心化后的相对贡献值,需要和预测用的newdata按行绑定、补充置信区间计算后才能绘图。

实现步骤

1. 整理预测结果为绘图数据框

首先提取两个平滑项的拟合值、标准误,计算95%置信区间,和原预测数据集合并:

library(ggplot2)
library(dplyr)
library(tidyr)

# 提取预测值、标准误,计算置信区间
plot_data <- newdata %>%
  mutate(
    # 提取两个平滑项的拟合值
    smooth_timestep = preds$fit[, "s(timeStep)"],
    smooth_month = preds$fit[, "s(month)"],
    # 提取标准误
    se_timestep = preds$se.fit[, "s(timeStep)"],
    se_month = preds$se.fit[, "s(month)"],
    # 计算95%置信区间上下限
    timestep_lwr = smooth_timestep - 1.96 * se_timestep,
    timestep_upr = smooth_timestep + 1.96 * se_timestep,
    month_lwr = smooth_month - 1.96 * se_month,
    month_upr = smooth_month + 1.96 * se_month
  )

2. 分开展示两个平滑项(和内置plot(mod)效果一致)

把宽格式数据转成长格式,用分面分别绘制长期趋势、月份季节趋势:

# 宽转长适配分面
plot_data_long <- plot_data %>%
  pivot_longer(
    cols = c(smooth_timestep, smooth_month),
    names_to = "smooth_term",
    values_to = "fit_val"
  ) %>%
  mutate(
    # 匹配每个平滑项对应的x轴、置信区间
    x_val = ifelse(smooth_term == "smooth_timestep", timeStep, month),
    lwr = ifelse(smooth_term == "smooth_timestep", timestep_lwr, month_lwr),
    upr = ifelse(smooth_term == "smooth_timestep", timestep_upr, month_upr)
  )

# 绘图
ggplot(plot_data_long, aes(x = x_val, y = fit_val)) +
  geom_ribbon(aes(ymin = lwr, ymax = upr), fill = "grey80", alpha = 0.7) +
  geom_line(color = "red", linewidth = 1) +
  facet_wrap(~smooth_term, scales = "free_x",
             labeller = as_labeller(c(
               smooth_timestep = "s(timeStep) 长期趋势",
               smooth_month = "s(month) 季节趋势"
             ))) +
  labs(x = "变量取值", y = "平滑项中心化贡献值") +
  theme_bw()

运行后效果和内置plot输出一致,带置信区间阴影。

3. 同图展示趋势+季节效应

两个平滑项x轴量纲不同,同图展示更合理的方式是叠加得到最终拟合值,和原始观测、长期趋势对比:

# 提取模型截距,terms类型预测值加截距才是响应变量尺度的预测结果
mod_intercept <- coef(mod)[1]
plot_data <- plot_data %>%
  mutate(
    trend_only = mod_intercept + smooth_timestep,
    fit_total = mod_intercept + smooth_timestep + smooth_month
  )

ggplot(plot_data, aes(x = timeStep)) +
  geom_point(aes(y = co2), alpha = 0.3, size = 0.7) +
  geom_line(aes(y = trend_only, color = "长期趋势"), linewidth = 1) +
  geom_line(aes(y = fit_total, color = "叠加季节效应拟合值"), linewidth = 0.8) +
  scale_color_manual(values = c("长期趋势" = "red", "叠加季节效应拟合值" = "blue")) +
  labs(x = "时间步", y = "CO2浓度", color = NULL) +
  theme_bw()

注意事项

  • predict(..., type='terms')返回的所有平滑项结果均做了中心化处理(均值为0),单独表示该变量对预测结果的相对贡献,不能直接对应原始CO2浓度尺度,需要加模型截距、其他项的贡献才能得到实际预测值。
  • 月份是循环平滑项(bs="cc"),单独绘制月份效应时可以把x轴转为1-12的有序因子,更贴合月份的循环属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:03:18