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

添加国家因子后GAM模型绘图报错:美学属性y长度不匹配

GAM模型含国家因子后的绘图美学错误解决

问题描述

我在GAM模型中加入Country_Name作为因子来建模国家内部的关系(若此操作有误请指出),但绘图时抛出美学属性错误:

! Aesthetics must be either length 1 or the same as the data (480): y

现有代码与数据

模型代码

mod = gam(gdp_per_capita ~ s(fisheries_production_pc, k = 25, bs = 'cs') + as.factor(Country_Name), 
           data = economy_df, 
           family = gaussian(link = "log"))

#predictions
preds = predict(mod, type = 'response', se.fit = TRUE)

#plot model
plot = ggplot(economy_df, aes(y = gdp_per_capita, x = fisheries_production_pc)) +
geom_point() + 
geom_line(aes(fisheries_production_pc, preds$fit), colour = 'red') +
scale_x_log10()

数据片段

Country_Name year gdp_per_capita fisheries_production
Albania 1997       717.3800              1110.80
Albania 1998       813.7894              2807.50
Albania 1999      1033.2425              3057.90
Albania 2000      1126.6833              3635.00
Albania 2001      1281.6598              3597.20
Albania 2002      1425.1242              4516.80
Bosnia  1997       982.8018               253.00
Bosnia  1998      1102.3907               254.00
Bosnia  1999      1251.7476               255.00
Bosnia  2000      1484.1761               255.00
Bosnia  2001      1544.6021               255.00
Croatia 1997      5312.3695             20551.49
Croatia 1998      5691.1095             27935.08
Croatia 1999      5246.9360             25222.19
Croatia 2000      4887.7137             27944.24
Croatia 2001      5412.9251             29019.12
Cyprus 1997     14234.2441             25788.00
Cyprus 1998     15092.8262             20482.00
Cyprus 1999     15287.9189             41060.00
Cyprus 2000     14388.3477             70223.00

错误原因

你猜的没错:加入国家因子后,模型的预测值是分国家的分组结果,但原绘图代码存在两个问题:

  1. geom_line继承了全局aes中的y = gdp_per_capita,同时又在自己的aes里指定y = preds$fit,导致美学属性冲突;
  2. 没有按Country_Name分组,ggplot无法识别每个预测值对应的国家,线条绘制逻辑混乱。

另外注意:模型里用了fisheries_production_pc,但数据片段里只有fisheries_production,推测是笔误,后续代码默认你已经处理好这个变量。

修正后的绘图代码

第一步:绑定预测值到原数据框

先把预测值和原数据合并,确保每个观测对应自己的预测值,保留国家分组信息:

economy_df$pred_fit = preds$fit
economy_df$pred_se = preds$se.fit

第二步:按国家分组绘制拟合线

因为模型给每个国家加了独立截距,所以需要按国家分组绘制拟合线,修正美学映射:

library(ggplot2)
library(mgcv)

# 基础绘图:点+分国家拟合线
plot = ggplot(economy_df, aes(x = fisheries_production_pc, y = gdp_per_capita)) +
  geom_point(aes(color = Country_Name), alpha = 0.6) +  # 点按国家上色,方便区分
  geom_line(aes(y = pred_fit, color = Country_Name), linewidth = 1) +  # 按国家分组画拟合线
  scale_x_log10() +
  labs(x = "人均渔业产量", y = "人均GDP", color = "国家") +
  theme_minimal()

print(plot)

可选:添加95%置信区间

如果需要展示预测的不确定性,加上geom_ribbon:

# 带置信区间的绘图
plot = ggplot(economy_df, aes(x = fisheries_production_pc, y = gdp_per_capita)) +
  geom_point(aes(color = Country_Name), alpha = 0.6) +
  geom_ribbon(aes(ymin = pred_fit - 1.96*pred_se, ymax = pred_fit + 1.96*pred_se, fill = Country_Name), alpha = 0.2) +
  geom_line(aes(y = pred_fit, color = Country_Name), linewidth = 1) +
  scale_x_log10() +
  labs(x = "人均渔业产量", y = "人均GDP", color = "国家", fill = "国家") +
  theme_minimal()

print(plot)

关于模型的小建议

你用as.factor(Country_Name)加入国家固定效应的方式没问题。如果国家数量较多,推荐改用随机效应建模,能减少自由度消耗,更符合国家间截距存在变异的假设:

mod = gam(gdp_per_capita ~ s(fisheries_production_pc, k = 25, bs = 'cs') + s(Country_Name, bs = 're'), 
           data = economy_df, 
           family = gaussian(link = "log"))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:55:36