如何使用ggplot和ggfortify为第二幅图添加Cook's距离红色虚线等高线?
如何用ggplot2和ggfortify添加Cook's距离等高线到回归诊断图
没问题,我来帮你搞定这个Cook's距离等高线的添加!其实核心是先理清Cook's距离和学生化残差、杠杆值的数学关系,然后基于这个关系生成等高线数据,再把它叠加到ggfortify的诊断图上就行。
先搞懂Cook's距离的等高线公式
Cook's距离的计算公式是:
D_i = (r_i² / p) * (h_ii / (1 - h_ii)²)
其中:
r_i:第i个样本的学生化残差h_ii:第i个样本的杠杆值(帽子矩阵的对角线元素)p:模型的参数总数(包含截距项)n:样本量
常用的Cook's距离临界值是 4/n(经验规则),我们要画的就是所有满足 D_i = 4/n 的点组成的曲线。把公式变形一下,就能得到学生化残差和杠杆值的关系:
r = ±√[ (4/n) * p * (1 - h)² / h ]
有了这个关系,我们就能生成等高线的坐标数据了。
具体代码实现(用mtcars数据集演示)
1. 准备模型和诊断数据
先拟合模型,提取我们需要的统计量:
library(ggplot2) library(ggfortify) library(dplyr) library(broom) # 拟合线性模型 model <- lm(mpg ~ wt + hp, data = mtcars) # 提取诊断数据:学生化残差、杠杆值、参数数、样本量 diagnostics <- augment(model) %>% mutate( leverage = hatvalues(model), student_resid = rstudent(model), p = length(coef(model)), n = nrow(mtcars) )
2. 生成Cook's距离等高线数据
基于上面推导的公式,生成等高线的坐标点:
# 定义Cook's距离临界值 critical_D <- 4 / diagnostics$n[1] # 生成杠杆值的序列(覆盖现有数据的杠杆值范围) h_seq <- seq(min(diagnostics$leverage), max(diagnostics$leverage), length.out = 100) # 计算对应学生化残差的上下边界 r_upper <- sqrt(critical_D * diagnostics$p[1] * (1 - h_seq)^2 / h_seq) r_lower <- -r_upper # 整理成ggplot可用的数据框 cook_contour_df <- data.frame( leverage = rep(h_seq, 2), student_resid = c(r_upper, r_lower) )
3. 叠加等高线到ggfortify的诊断图
用autoplot生成残差-杠杆图,再用geom_path添加红色虚线等高线:
autoplot(model, which = 5, label.size = 3) + geom_path( data = cook_contour_df, aes(x = leverage, y = student_resid), color = "red", linetype = "dashed", linewidth = 1 ) + labs(title = "学生化残差 vs 杠杆值(含Cook's距离等高线)")
另一种方法:用geom_contour直接绘制
如果你更习惯用geom_contour,可以先生成一个网格数据集,计算每个网格点的Cook's距离,再提取临界值对应的等高线:
# 生成覆盖残差和杠杆值范围的网格 grid_data <- expand.grid( leverage = seq(min(diagnostics$leverage), max(diagnostics$leverage), length.out = 100), student_resid = seq(min(diagnostics$student_resid), max(diagnostics$student_resid), length.out = 100) ) %>% mutate( # 计算每个网格点的Cook's距离 cook_d = (student_resid^2 / diagnostics$p[1]) * (leverage / (1 - leverage)^2) ) # 绘制图并添加等高线 autoplot(model, which = 5, label.size = 3) + geom_contour( data = grid_data, aes(x = leverage, y = student_resid, z = cook_d), breaks = critical_D, color = "red", linetype = "dashed", linewidth = 1 ) + labs(title = "学生化残差 vs 杠杆值(含Cook's距离等高线)")
注意事项
- 临界值
4/n是经验规则,你也可以根据需求换成其他值(比如1),只需要修改critical_D的赋值即可。 - 确保你用的残差和杠杆值和ggfortify的图一致:
autoplot(model, which=5)展示的是学生化残差和杠杆值,所以我们用rstudent(model)和hatvalues(model)是完全匹配的。 - 如果你的模型没有截距项,记得调整
p的计算(去掉截距的参数数)。
内容的提问来源于stack exchange,提问作者Hasnep
相关产品推荐
相关产品推荐

