ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

R语言线性回归诊断:四张图掌握残差、正态性与异方差

R语言线性回归诊断:四张图掌握残差、正态性与异方差 刚开始用R语言做线性回归的时候我跟很多人一样跑完lm()之后第一时间盯住summary()的结果满眼都是星星、p值和R方。后来在真实项目里吃了几次亏才意识到一个关键问题summary()回答的是拟合效果好不好的程度但它不告诉你这些系数、p值、置信区间到底可不可信。线性回归的所有推断都建立在几个前提假设上而这些假设有没有被破坏靠的是一组专门的模型诊断图——也就是标题里提到的Residuals vs Fitted、Normal QQ、Scale-Location、Residuals Leverage这四张图。这篇文章就把这四张图彻底讲透每张图是怎么画的、正常长什么样、异常代表什么问题、发现问题之后具体怎么补救。我会用R内置数据集做完整演示也会把我在实际分析中踩过的坑一起放进来。无论你是刚接触R语言的数据分析新人还是已经能跑通回归但总怀疑这模型到底行不行的进阶用户这篇文章都适合你。1. 为什么线性回归跑完不能急着看系数诊断图到底在看什么1.1 线性回归的前提假设与体检思维线性回归模型写出来很简单[ y \beta_0 \beta_1 x_1 \dots \beta_p x_p \varepsilon ]但普通最小二乘法OLS要给出可信的系数估计和显著性检验背后是有硬性条件的。统计推断依赖的核心假设有四条线性性因变量和自变量之间是线性关系或者至少当前变量形式下没有明显的非线性结构残留。独立性不同观测的随机误差彼此独立。同方差性随机误差的方差在不同拟合值水平上基本恒定。正态性随机误差服从正态分布尤其是做小样本推断时。这四条假设有点像体检的几个核心指标。一个人脸色好不好R方高不高不能反映全部健康问题血脂、血压、肝功能得分开查。诊断图就是这个思路每一张图负责检查一个或几个假设合在一起才是一个完整的体检报告。1.2 plot(model)一次生成的四张图分别对应哪些假设在R里对lm对象直接使用plot()函数R会按照默认配置依次画出多张诊断图。很多人都知道有四张图但很多人不知道一个细节R默认的plot.lm()方法实际选的which c(1:3, 5)也就是说真正默认展示的是下面四张默认顺序图名检查重点默认which参数1Residuals vs Fitted线性性、是否有系统模式12Normal QQ残差正态性23Scale-Location同方差性异方差34Residuals vs Leverage强影响点、高杠杆点5这里特别容易踩一个坑默认四张图里并不包含单独的Cook距离图which 4。很多教程把第四张图说成Cook距离图严格来说是不准确的。默认第四张是Residuals vs Leverage它把杠杆值、标准化残差和Cook距离三条信息叠在一张图里比单独的Cook距离图信息量更大。这个细节后面我会专门展开。1.3 为什么不能只看R方和显著性一个常见误区是R方都0.9了模型还能有问题答案是完全有可能。R方只说明自变量对因变量变异的解释比例它不关心残差里是否藏着系统性结构。统计学里有个著名的anscombe数据集四组数据的R方、回归系数、p值几乎完全一样但把散点图画出来四组数据的形态天差地别一组是标准线性一组是明显的曲线一组被一个离群点控制还有一组根本就是竖线加一个孤立点。这个例子在R里一行代码就能复现data(anscombe)然后分别拟合四个lm你就能亲眼看到同样的统计量、完全不同的模型质量。如果残差里有明显的非线性结构或者方差随拟合值增大而扩大那么系数的标准误、p值、置信区间都会失真预测区间更是不可信。这就是为什么诊断图不是可选的额外检查而是线性回归使用流程里必须的一步。2. 第一张图Residuals vs Fitted线性关系和等方差的第一现场2.1 这张图是怎么构造的Residuals vs Fitted通常简称为残差-拟合图横轴是模型对每个样本的拟合值(\hat{y})纵轴是普通残差(e_i y_i - \hat{y}_i)。图里除了散点还会有一条红色平滑曲线R默认用lowess局部加权回归来拟合残差和拟合值的关系。你可能会问为什么用残差对拟合值作图而不是直接对每个自变量分别作图原因很实际拟合值是所有自变量的线性组合相当于把多个维度的信息压缩到了一根横轴上。一张图就能看出整体趋势比逐个画残差对(x_j)的图更高效。当然如果残差-拟合图发现问题后续再对单个自变量单独画残差图做精确定位这属于正常的深入排查。2.2 三种典型形态随机云、喇叭形、弯曲形正常情况下残差应该在0线附近随机散落红色平滑曲线基本贴近水平线看不出明显的趋势。就像撒了一把豆子没有聚堆也没有规律。如果残差点带呈现明显的喇叭形也就是拟合值增大时散点上下波动范围越来越大这是异方差的经典信号。可以这样理解模型对小数值预测得比较稳对大数值预测越来越没谱。这种情况下lm()仍然能给出无偏的系数估计但标准误会估计不准通常被低估导致原本不显著的变量被判成显著。如果红色平滑曲线呈现出U形、倒U形或S形说明线性结构没有完全捕捉数据模式。最常见的原因是缺少自变量的二次项或更高次项比如收入和消费的关系往往边际递减用直线硬拟合就会在残差里留下弯曲。缺少交互项某个自变量的效应在另一个变量的不同水平上不一样。因变量或自变量需要做对数、倒数等变换比如生物、经济数据里常见的对数线性关系。2.3 残差图出现规律性弯曲时怎么补救遇到弯曲形态我的建议是不要着急否定模型先按这个顺序排查看有没有明显的变量漏掉尤其是时间、空间这类结构性变量。尝试在模型中加入自变量的二次项比如y ~ x I(x^2)。尝试对因变量取对数或者对高偏态的自变量取对数。用AIC或anova()对嵌套模型做比较确认加入新项后是否有实质改善。举个例子用mtcars数据拟合mpg ~ hp时很多人第一次画残差图就会发现点带呈弯曲状原因是马力对油耗的影响明显边际递减。改成mpg ~ hp I(hp^2)后残差图会明显改善。这在实际项目中非常常见——线性假设不成立不一定是变量选错了更可能是变量形式不对。3. 第二张图Normal QQ残差正态性没那么玄3.1 QQ图的构造原理Normal QQ图的完整名称是分位数-分位数图它把残差的实际分布和理论正态分布放在一起比较。具体做法是先把残差从小到大排序计算每个排序位置的累计概率再换算成标准正态分布对应分位数以理论分位数为横轴、样本分位数为纵轴画散点。如果残差真的来自正态总体散点会紧密贴在同一条45度参考线附近。R在绘制QQ图时会用标准化残差而不是普通残差并且自动画出一条参考线这条参考线不是对角线而是穿过第一四分位数和第三四分位数的直线。这样即使残差整体偏移参考线也能贴合数据的整体位置方便看偏离。3.2 尾部偏离怎么解读QQ图最关心的是尾部行为。中间的点偏离一点通常问题不大但两端的点如果系统性偏离参考线就要留意上端向上翘残差右尾比正态分布更厚说明存在大的正残差实际值明显高于预测值。下端向下垂左尾厚存在大的负残差。两端都偏离但方向相反整体呈S形或反S形分布可能存在偏斜。个别点明显脱离直线这些点很可能是离群值R会在旁边标出观测的行号方便你定位。读QQ图时我的习惯是先看整体趋势再看被标记的离群点。不要因为某个点在线上稍微偏一点就紧张更要避免完全无视严重的尾部偏离。3.3 什么时候需要真正紧张很多人对正态性假设有执念总觉得残差不完全正态模型就没法用了。这里需要澄清一个事OLS的系数估计本身对正态性偏离有一定耐受性特别是样本量足够大时中心极限定理会帮我们兜底系数估计的分布仍然近似正态z检验、t检验的结论大体可靠。真正需要重视正态性的场景是样本量很小比如n30此时中心极限定理不一定有效。需要做预测区间或置信区间这些区间对分布假设更敏感。残差存在极其严重的重尾极端值过多导致标准误严重膨胀。如果QQ图显示偏斜较重可以考虑对因变量做Box-Cox变换MASS包里有现成的boxcox()函数它会自动搜索最优的变换参数λ。变换后重新拟合通常QQ图会明显好转。4. 第三张图Scale-Location异方差的高清检测4.1 为什么纵轴是标准化残差的绝对值开方Scale-Location图很多人第一次看到时会困惑纵轴不像普通残差而是一个不太眼熟的指标。R画这张图时纵轴是(\sqrt{|standardized\ residuals|})也就是标准化残差的绝对值再开平方根。这么设计有两个原因。第一标准化残差已经把残差除以了标准误的估计值并且考虑了杠杆值的影响不同样本的残差可以在同一尺度上比较比普通残差更适合判断方差是否恒定。第二开平方根是一种方差稳定化变换可以压缩较大残差对图的影响避免一两个大离群点把整张图的尺度拉爆导致看不出整体趋势。横轴依然是拟合值。红色平滑曲线同样是lowess趋势线。所以这张图的核心任务很纯粹看残差的波动幅度是否随拟合值变化。4.2 怎么判断有没有异方差读图标准可以记成一句话红线越平越好。红线基本水平且点带宽度在各处差不多方差稳定满足同方差假设。红线随拟合值增大而向上倾斜方差随拟合值增大这是最常见的异方差模式。红线随拟合值增大而向下倾斜方差随拟合值减小相对少见。红线在某个区间突然扬起通常是有高杠杆点或强影响点在拉动趋势线注意看被标记的序号。这张图比第一张图判断异方差更可靠。Residuals vs Fitted图里如果出现喇叭形说明异方差明显但有些时候喇叭形并不清晰点带看着差不多这时候就要靠Scale-Location图来精确定位方差趋势。两张图结合看比只看一张更有把握。4.3 确认异方差后的处理路径如果诊断图确认存在异方差处理方案有三种常见路线第一种变量变换。对因变量做对数、平方根或Box-Cox变换这是最常用的手段。比如因变量是收入、房价、销售额这类右偏数据取对数后往往既能改善线性性也能稳定方差。第二种加权最小二乘WLS。如果你知道方差异质性的来源比如方差与某个变量成正比可以给不同样本赋予不同权重用lm(y ~ x, weights w)拟合。第三种稳健标准误。系数估计不变但用sandwich包里的vcovHC()算出异方差稳健的标准误再配合lmtest::coeftest()重做显著性检验。这在经济学领域几乎是标准操作简单高效不需要改变模型结构。需要提醒的是如果Residuals vs Fitted图同时显示弯曲和喇叭形那不能只处理异方差还要先解决非线性。因为错误的结构本身就会制造残差模式导致方差看起来不稳。顺序应该是先修正模型结构再检查方差最后再判断要不要动推断方法。5. 第四张图Residuals Leverage找出真正影响模型的坏学生5.1 杠杆值、残差与Cook距离的关系Residuals vs Leverage图是默认四张图里信息最密集的一张。横轴是杠杆值leverage(h_{ii})纵轴是标准化残差图里还叠加了Cook距离等值线。杠杆值刻画的是第(i)个样本在自变量空间中的偏远程度。如果一个样本的(x)值和其他样本差异很大它的杠杆值就会偏高。样本杠杆值的平均水平大约是((p1)/n)其中(p)是自变量个数(n)是样本量。比如模型有3个自变量、样本量50平均杠杆大约0.08超过这个值两三倍的样本就需要留意。Cook距离是综合了杠杆值和残差大小两个维度的指标粗略的公式可以理解为[ D_i \approx \frac{r_i^2}{p1} \times \frac{h_{ii}}{1 - h_{ii}} ]其中(r_i)是标准化残差。看这个式子能发现两件事残差大能抬高Cook距离杠杆高也能抬高Cook距离。如果一个点杠杆又高、残差又大那它几乎一定是强影响点。5.2 图里的虚线等值线怎么读在Residuals vs Leverage图中R会用虚线画出Cook距离的等值线。很多人看到虚线不知道该怎么用。经验法则是样本点在两条虚线围成的区域内部影响相对可控。点落在虚线上或外面Cook距离较大需要重点检查。Cook距离超过1的样本通常被认为对回归系数有实质影响应该单独分析。不过这个1是经验阈值不要机械执行。在样本量不大时哪怕Cook距离只有0.5也足以让某个关键系数发生明显变化。更稳妥的做法是先用cooks.distance(model)把所有样本的Cook距离排序再结合具体业务判断该点是否异常。5.3 高杠杆点不等于高影响点这个区别很关键我见过很多初学者把高杠杆点直接等同于坏点这是最常见的误解之一。高杠杆只说明这个样本在X空间里离群但如果它的y值和模型预测吻合它反而可能是在支撑模型的关键样本。真正危险的是高杠杆大残差的组合也就是x偏远、y还预测不准这种点会像跷跷板的一端把回归线硬生生拉向自己。拿班级成绩打比方一个坐在教室角落的同学只是位置离大家远这本身不影响全班平均分但如果这个角落里的同学突然考了满分或者零分那全班平均分就会被明显带动。高杠杆是位置特殊强影响是我的特殊位置加上我的极端表现让整个模型跟着我走。在报告分析结果时如果删掉某个样本后系数方向或显著性发生改变不要悄悄把它删了。正确的做法是在文档里明确说明该样本对结果存在较大影响剔除后结论依然稳健或剔除后结论不再稳健因此此处展示的是包含该样本的结果这样别人才会信任你的分析。6. 用mtcars数据完整跑一遍诊断流程6.1 数据与初始模型理论说了不少接下来用一个真实的R内置数据集走一遍完整流程。mtcars大家应该很熟32条汽车观测包含油耗、马力、重量、排量等变量。我们用mpg作为因变量wt重量、hp马力、disp排量作为自变量建立一个基础线性回归。data(mtcars) m1 - lm(mpg ~ wt hp disp, data mtcars) summary(m1)跑完summary()你会看到整体F检验显著R方接近0.85看起来是个不错的模型。但先别高兴太早马上画诊断图par(mfrow c(2, 2)) plot(m1)6.2 逐图看问题我在实际跑这个模型时四张图暴露的问题很明显。第一张Residuals vs Fitted图里红色平滑曲线并不是一条干净的水平线在高拟合值区域出现了一定弯曲说明mpg和自变量之间可能不是纯线性关系。第二张QQ图整体还可以但尾部有个别点偏离参考线特别是高拟合残差的那一侧。第三张Scale-Location图里红线有轻微上扬趋势存在一定异方差的苗头。第四张Residuals vs Leverage图更直白Maserati Bora、Ford Pantera L这类大马力车型因为hp和weight都很极端杠杆值明显高于其他样本个别点已经靠向Cook距离等值线。顺带补充一个很容易被忽略的问题wt和disp的相关系数高达0.89hp和disp的相关系数也有0.79。这意味着模型里存在明显的多重共线性summary()中的单变量系数标准误已经不可靠。round(cor(mtcars[, c(wt, hp, disp)]), 2)多个自变量高度相关时系数估计的方差会被放大单个变量的是否显著变得极不稳定。这也是为什么诊断不能只看残差图还要结合相关矩阵和VIF一起看。6.3 针对性修正模型既然发现问题我先把高相关的disp拿掉保留wt和hp再根据残差图的弯曲提示加入wt的二次项让模型能够捕捉非线性关系。m2 - lm(mpg ~ wt I(wt^2) hp, data mtcars) summary(m2)对比m1和m2anova(m1, m2)anova的p值如果很小说明加入wt^2有实质改善。实际运行中m2的残差图明显比m1干净Residuals vs Fitted的红线更平Scale-Location图的上扬趋势也减弱了。这再次验证了一个经验很多看似异方差的问题根源其实是模型结构错误。先修结构再判断方差是否真正不稳。6.4 若仍有异方差用稳健标准误做推断如果修完结构后Scale-Location图仍然提示异方差有“高杠杆大残差”的样本存在我不会急着删点更不会强行做加权最小二乘一锤定音。稳妥的做法是用稳健标准误重新做一遍显著性检验看结论是否发生变化。library(sandwich) library(lmtest) coeftest(m2, vcov vcovHC(m2, type HC1))对比普通summary(m2)和稳健标准误的结果如果系数的显著性没有发生戏剧性变化那对模型结论就可以多一点信心如果某变量从显著变成不显著说明这个结论本身是脆弱的需要进一步排查样本点的影响。关于强影响点还可以这样定位cooks.distance(m2) | sort(decreasing TRUE) | head()把Cook距离最大的几个样本拎出来结合原始数据看它们的实际含义。比如某个跑车样本功率极大、油耗也异常高它确实在拖低回归面但从业务角度它又是一个真实存在的车型不能简单删除。这时候要么在报告中专门说明要么做一次删点稳健性检验。7. 实际使用中的高频疑问与避坑经验7.1 为什么我plot(model)一次看不到四张图这是RStudio新手最常见的困惑。plot.lm()默认会连续绘制多张图如果终端窗口不够大R会停下来提示Hit Return to see next plot按一下回车才能继续看下一张。如果在脚本里运行想一口气把四张图放在同一张画布上用这个par(mfrow c(2, 2)) plot(m1)把图形窗口设置为2x2网格后四张图会并排展示方便对照阅读。如果用RStudio直接在Plots面板里用箭头翻页也一样。7.2 大样本时点云重叠严重怎么办当样本量到几万甚至几十万时诊断图会糊成一团黑色根本没法看。这时候有两个办法一是对数据进行随机抽样比如从10万条里随机抽2000条再画诊断图趋势不会变二是用分箱残差图把拟合值分成几十个区间计算每个区间的平均残差再画出来相当于对趋势线做了更稳健的估计。broom包配合dplyr分箱操作就能实现。7.3 缺失值处理对诊断图的影响线性回归遇到缺失值时lm()默认使用na.omit做行删除这是静默行为。如果你在建模前手动处理过缺失值但画诊断图时又用了包含缺失值的原始数据框会导致样本对不上某些点在残差图上被错误标注。我在项目里就踩过这个坑na.omit之后的行名已经改变plot()里标出的行号和原始数据行号对不上排查离群点时找不到人。建议建模前统一做好缺失值处理全程使用同一个数据框并且保留行名设定。7.4 关于删离群点的慎重态度最后想说一个老生常谈但必须说的问题不要看到Cook距离大就删点。删除一个强影响点之前先问自己三个问题这个样本的数值是不是录入错误或测量错误如果是可以修正或删除。这个样本是否来自一个真实存在但特殊的群体比如豪华跑车、极端地理区域如果是删掉它会损失信息。删除后结论是否改变如果改变说明模型对单个样本过度敏感应该在报告中公开这个敏感性。我个人的底线是永远不要把删点当作解决模型问题的默认手段。优先尝试变量变换、加入非线性项、使用稳健推断只有在确认数据本身存在错误且删除有明确业务理由时才去动样本。否则你的模型就会变成删到什么程度好看就删到什么程度这在任何正式分析报告里都是说不出口的。7.5 一个实用的日常读图顺序最后分享一个我自己固定使用的读图顺序。每拟合完一个模型我不会一张一张地盯着研究而是按整体→异常→细节的顺序快速扫一遍先看Residuals vs Fitted的红线平不平不平说明结构有问题再看QQ图两端有没有大规模离群有离群说明分布假设可能被破坏接着看Scale-Location的红线抬升幅度判断方差是否稳定最后看Residuals vs Leverage图里有没有点靠近或越过Cook距离等值线。四张图全部过关才放心看summary()的系数。如果发现任何一张图有异常就回头改模型改完必须重新plot()一遍确认问题真的消失而不是只看summary()的AIC下降了就觉得万事大吉。在实际项目里诊断图最宝贵的价值不是帮你追求一个数学上完美的模型而是帮你建立一种直觉哪些结论是稳健的哪些结论是牵一发动全身的。带着这种直觉去分析数据比背下一堆统计检验公式重要得多。
返回列表