如何从ggplot2的geom_smooth模型中提取标准差?(二次拟合场景)
解决二次拟合时geom_smooth提取标准差不一致的问题
问题根源
你之前用的ymin=after_stat(y-se*sqrt(length(y))逻辑不成立,因为:
geom_smooth中的se是模型预测值的标准误(Standard Error),反映拟合线本身的不确定性(和模型参数方差相关);- 你需要的**观测数据的标准差(Standard Deviation)**是原始数据围绕拟合线的离散程度,对应模型的残差标准差(σ);
- 仅在简单线性回归(
y~x)的特殊场景下,se*sqrt(n)才近似等于残差标准差,但二次拟合(y ~ x + I(x^2))属于非线性模型,两者的转换关系完全不适用,因此会出现结果不一致的情况。
正确解决方案
步骤1:拟合模型并提取残差标准差
先通过lm()拟合二次模型,用sigma()提取残差标准差——这就是你要的观测数据围绕拟合线的离散程度:
library(ggplot2) # 示例数据(替换成你的数据) set.seed(123) x <- seq(0, 10, length.out = 100) y <- 2 + 3*x - 0.2*x^2 + rnorm(100, 0, 2) df <- data.frame(x, y) # 拟合二次模型 model <- lm(y ~ x + I(x^2), data = df) # 提取残差标准差 resid_sd <- sigma(model)
方式一:手动计算区间后绘图(更灵活)
生成拟合值和对应的标准差区间,用geom_line和geom_ribbon绘制:
# 生成预测用的x序列 new_x <- seq(min(df$x), max(df$x), length.out = 100) pred_df <- data.frame(x = new_x) # 计算拟合值 pred_df$fit <- predict(model, newdata = pred_df) # 计算±1倍残差标准差的区间 pred_df$ymin <- pred_df$fit - resid_sd pred_df$ymax <- pred_df$fit + resid_sd # 绘图 ggplot(df, aes(x, y)) + geom_point(alpha = 0.5) + geom_line(data = pred_df, aes(y = fit), color = "blue", linewidth = 1) + geom_ribbon(data = pred_df, aes(ymin = ymin, ymax = ymax), alpha = 0.2, fill = "blue")
方式二:直接在geom_smooth中使用残差标准差
如果想保留geom_smooth的语法,可以关闭默认的se,手动指定基于残差标准差的区间:
ggplot(df, aes(x, y)) + geom_point(alpha = 0.5) + geom_smooth(method = "lm", formula = y ~ x + I(x^2), aes(ymin = after_stat(fit) - resid_sd, ymax = after_stat(fit) + resid_sd), se = FALSE, color = "blue", fill = "blue", alpha = 0.2)
关键说明
- 残差标准差
sigma(model)是全局的,代表整个数据集围绕拟合线的平均离散程度; - 如果你的数据存在异方差(不同x对应的离散程度不同),可以考虑用
predict(model, interval = "prediction")生成预测区间,它会结合预测值的标准误和残差标准差,更准确反映单个观测的不确定性。
内容的提问来源于stack exchange,提问作者Sibylle Stöckli
相关产品推荐
相关产品推荐

