回归分析是把「找一条线」变成一套能报数字的流程:系数、标准误、t 值、R²。四个数各管一头, 缺一个就会误判。 这一节的重点不是公式,是三件常被忽略的事: R² 只涨不跌、共线性让解释失效、参数个数追上样本个数就是灾难。
上一节说清了一条线的能力边界。这一节把「怎么用这条线」讲成一套能报数字的流程。 标准误这一套后面会反复用:第 7 章比两个模型谁更好,第 8 章判断策略差异是不是噪声, 用的都是同一个思路 —— 先算不确定度,再比大小。
一、四个数字,各管一头
一份正经的回归结果至少报四样东西,它们回答的是四个不同的问题:
| 数字 | 回答的问题 |
|---|---|
| 系数 | 自变量每变一个单位,y 平均变多少 |
| 标准误 | 换一批数据重来,这个系数会晃多少 |
| t 值 | 系数除以标准误,信号比噪声 |
| R² | 这条线解释了多少波动 |
标准误不是估的,是算的:s²(X'X)⁻¹ 的对角线开根号。其中 s² 是残差方差。 |
|
这个式子里 (X'X)⁻¹ 那一项,后面会变成共线性的全部麻烦来源。 |
|
| t 值的用法很朴素:绝对值大于 2 就大致算「显著」。这条经验法则来自正态分布 —— | |
| 两倍标准差以外的概率约 5%。它不是金标准,但对大多数样本量够的场合够用。 |
二、标准误和 R² 是两件事
Demo 第一段:40 个点,真规律 y = 3 + 1.8x。
拟合出斜率 1.7880、标准误 0.0305、t 值 58.59、R² 0.9891。
斜率比真值小 0.0120,看着像有偏差。
可把它除以标准误,只有 0.39 —— 这点偏差完全在噪声能解释的范围里。
R² 0.9891 说的是「这条线解释了 98.9% 的波动」;
标准误 0.0305 说的是「换一批数据重来,斜率会在 1.79 上下晃 0.03」。一个讲拟合得好不好,
一个讲结论稳不稳。两个都重要,但用途不同。
做预测时看 R²,做决策时看标准误。「这个广告投下去能涨多少销量」要的是系数加标准误,
「这条线能不能替代实验」才看 R²。
三、加一个没用的特征,R² 一定涨
Demo 第二段往模型里塞了一串纯随机数。结果:
| 原模型 | 新模型 | |
|---|---|---|
| R² | 0.9891 | 0.9894 |
| x1 的斜率 | 1.7880 | 1.7864 |
| 随机数的 t 值 | — | +1.11 |
| R² 涨了 0.0003 —— 涨得少,但它只会涨不会跌。这是 R² 的结构决定的:多加一列, | ||
| 残差平方和一定不会变大。所以拿 R² 比模型,永远偏向更复杂的那个。 | ||
| 真正的判据是那个 t 值:1.11。约等于 1 的 t 值说明这个系数跟零分不出来 —— | ||
| 这一列没有携带信息。 | ||
| 这就是为什么正经的回归表格从不只报 R²。想比模型好坏,得用「调整 R²」(按参数个数打折)、AIC、 | ||
| 或者干脆留出测试集。这三个办法做的是同一件事:惩罚复杂度。 |
四、共线性:预测还挺准,解释全废
Demo 第三段造了一个 x2 = 0.98·x1,跟 x1 的相关系数 0.9990。
x2 一点用都没有,规律还是 y = 3 + 1.8x1。
| 模型 | x1 系数 | 标准误 | t 值 |
|---|---|---|---|
| 只放 x1 | 1.7880 | 0.0305 | 58.59 |
| x1 和 x2 一起 | 0.2342 | 0.7128 | 0.33 |
| R² 从 0.9891 变成 0.9888,几乎没动 —— 模型没变强也没变弱。 | |||
| 可 x1 的系数从 1.7880 掉到 0.2342,标准误从 0.0305 涨到 0.7128,涨了 23 倍, | |||
| t 值从 58.59 掉到 0.33。 | |||
| 要两个系数一起看才明白:x2 的系数是 1.5853,两个数「合用」一个 1.8。 | |||
| 最小二乘不知道该把功劳分给谁,于是给出一个随机的分法。换个随机种子,这两个数会跑到别的地方去。 | |||
| 这就是共线性。它的后果不是预测变差(R² 还在 0.99),而是解释变废: | |||
| 你说不出到底是 x1 在起作用还是 x2。 | |||
| 而且两个 t 值都变得不可信 —— 明明两个变量合起来非常显著,单独看却都不显著。 | |||
| 判断办法很土但很准:把两个几乎一样的特征分别单独放进模型, | |||
| 如果系数差得离谱,它们就共线了。真实数据里共线性极常见(身高和体重、气温和用电量、 | |||
| 同一种指标的不同测法),看到系数符号跟常识反着走,第一个要怀疑的就是它。 |
五、参数个数追上样本个数
Demo 第四段:10 个点,来自 sin(2πx) 加噪声,用 9 次多项式去配。
训练点上最大误差 4.25e-11,等于零。新点上最大误差 1.10 ——
sin 的取值本来只在 −1 到 1 之间。
Demo 第五段逐次加高,看两条误差怎么分岔:
| 次数 | 训练误差 | 新点误差 |
|---|---|---|
| 1 | 0.6263 | 0.7554 |
| 3 | 0.1913 | 0.3341 |
| 5 | 0.1756 | 0.3536 |
| 7 | 0.1600 | 0.3410 |
| 9 | 0.0000 | 1.1028 |
| 左边一列整体往下,最后落到 0;右边一列最低在 3 次(0.3341),之后一路涨回 1.1028。 | ||
| 两条曲线分岔的地方,就是「开始记噪声」的地方。 | ||
| 于是有一句反直觉的话:训练误差最小的模型,一定不是最好的模型。因为参数个数追上了样本个数, | ||
| 模型就有足够的自由度把每个点都穿过去 —— 包括那些本来就是噪声的点。 | ||
| 真实的数据分析里没有 sin 可以对照,所以靠的是另一套办法:留出一部分数据不看, | ||
| 用没看过的数据来挑次数。这就是训练集/验证集/测试集的来历,第 7 章会把它写成固定流程。 |
六、「回归」这个词是怎么来的
1886 年,高尔顿量了一千多对父子的身高,画成散点图,发现一件事: 父亲很高,儿子也高,但没有父亲那么高;父亲很矮,儿子也矮,但没那么矮。整体在往中间收。 他把这个现象叫「向平均回归」。后来的统计学家把这个词借过来, 专指「用一条线去拟合条件平均」—— 名字里那个「回归」早就不指身高了,可它留了下来。 顺带说一句:高尔顿当年的解释是错的。不是「高个子的儿子会变矮」,而是身高由很多因素共同决定, 极端值必然是「很多因素同时往一个方向偏」的结果,下一代这些因素重新抽一遍,自然就回到中间。 这叫「回归到均值」,是统计里最容易误解的一句话 —— 它说的是群体趋势,不是任何一个人的命运。
七、动手 Demo:四个数字、一个离群点、一条九次曲线
ols 这个函数把最小二乘的「附带产物」一次算全了:系数、系数标准误、R²。
核心只有三行 —— 解方程、算残差、用 s²(X'X)⁻¹ 求标准误。
后面几段共用同一批数据:40 个点、一条真直线,然后分别往里塞随机数、塞一个几乎重复的列、
把次数一路加高。每一段只改一个东西,这样差别才归因得清楚。
def ols(X, y):
"""最小二乘,顺带把标准误和 R² 一起算出来。"""
n, k = X.shape
w, *_ = np.linalg.lstsq(X, y, rcond=None)
res = y - X.dot(w)
sse = float(res.dot(res))
s2 = sse / (n - k) # 残差方差
cov = s2 * np.linalg.pinv(X.T.dot(X)) # 系数协方差阵
se = np.sqrt(np.diag(cov)) # 对角线开根号就是标准误
r2 = 1.0 - sse / float(((y - y.mean()) ** 2).sum())
return w, se, r2
# 逐次加高,看训练误差和新点误差怎么分岔
for d in range(1, 10):
X = np.column_stack([xs ** p for p in range(d + 1)])
w, *_ = np.linalg.lstsq(X, ys, rcond=None)
e_in = np.abs(X.dot(w) - ys).max() # 训练点上
e_out = np.abs(Xt.dot(w) - truth).max() # 新点上
实跑输出:
--------------------------------------------------------------------
把一堆点压成一条线
--------------------------------------------------------------------
==============================================================
[1] 一元回归:斜率、截距,还有「这个斜率有多准」
40 个点,y = 3 + 1.8x 再加一点噪声。最小二乘给出的结果:
估计值 标准误 t 值
----------------------------------------------------------
截距 3.0616 0.1773 17.27
斜率 1.7880 0.0305 58.59
R² = 0.9891,残差标准误 = 0.5713,自由度 = 38
斜率 1.7880,真值 1.8,差 0.0120;它的标准误是 0.0305。
差除以标准误得 0.39 —— 这点偏差完全在噪声能解释的范围里。
R² 和标准误说的不是一件事:
R² 说「这条线解释了多少波动」,标准误说「换一批数据重来,
这个系数会晃多少」。前者是拟合得好不好,后者是结论稳不稳。
标准误是算出来的,不是估的:s²(X'X)⁻¹ 的对角线开根号。
这个式子后面还要用——[3] 段那个「涨了二十多倍」就是从它来的。
[2] 加一个跟 y 没关系的特征
原模型:y ~ x1
R² = 0.9891,残差标准误 0.5713,斜率标准误 0.0305
新模型:y ~ x1 + 一串纯随机数
R² = 0.9894,残差标准误 0.5696,斜率标准误 0.0305
原模型 新模型
----------------------------------------------
x1 的斜率 1.7880 1.7864
随机数的斜率 — +0.1361
随机数的 t 值 — +1.11
R² 从 0.9891 涨到 0.9894,涨了 0.0004。看着是进步,其实是假的:
随机数总能蹭到一点点相关性,R² 只会涨不会跌。
这就是为什么报回归结果一定要连标准误和 t 值一起报——
那个随机数的 t 值只有 1.11,一眼就看得出它没用。
[3] 两个自变量高度相关会怎样
造一个 x2 = 0.98·x1 再加微小扰动,跟 x1 的相关系数 0.9990。
真实规律还是 y = 3 + 1.8·x1,x2 一点用都没有。
模型 x1 系数 标准误 t 值
------------------------------------------------------
只放 x1 1.7880 0.0305 58.59
x1 和 x2 一起 0.2342 0.7128 0.33
R² 从 0.9891 变成 0.9888,几乎没动——模型没变强。
可 x1 的系数从 1.7880 掉到 0.2342,标准误从 0.0305 涨到 0.7128,涨了 23 倍,
t 值从 58.6 掉到 0.3。
同一模型里 x2 的系数 1.5853、标准误 0.7262、t 值 2.18。
两个系数一起看才明白:x2 其实就是 x1,它们只能「合用」一个 1.8。
最小二乘不知道该把功劳分给谁,于是给出一个随机的分法——
换个随机种子,这两个数会跑到别的地方去,而 R² 一动不动。
这叫共线性。后果不是预测变差(R² 还在 0.99),而是解释变废:
你说不出到底是 x1 在起作用还是 x2,两个 t 值也都不可信了。
判断办法很土但很准:把两个几乎一样的特征分别单独放进模型,
如果系数差得离谱,它们就共线了。
[4] 给 10 个点配一条 9 次曲线
10 个点,来自 sin(2πx) 加一点噪声。用 9 次多项式去配:
点数 10,待定系数 10 个
训练点上最大误差 4.25e-11
60 个新点上最大误差 1.1028
训练误差 4.25e-11,等于零——10 个点配 10 个系数,穿过它们是做得到的。
可在新点上它错到 1.10。sin 的取值本来只在 -1 到 1 之间。
看几个位置(新点都是没参与拟合的):
x = 0.03:真值 +0.166,9 次曲线 -0.181,差 -0.347
x = 0.26:真值 +0.998,9 次曲线 +0.860,差 -0.138
x = 0.51:真值 -0.052,9 次曲线 +0.075,差 +0.128
x = 0.74:真值 -0.998,9 次曲线 -0.659,差 +0.339
x = 0.97:真值 -0.166,9 次曲线 +0.936,差 +1.103
这不是「拟合得不够好」,是「拟合得太好了」。
参数个数追上样本个数,模型有了足够的自由度把噪声也当成规律记住。
于是有一句反直觉的话:训练误差最小的模型,一定不是最好的模型。
[5] 逐次加高:训练误差一路降,新点误差先降后升
次数 训练误差 新点误差
----------------------------------------
1 0.6263 0.7554
2 0.6800 0.7944
3 0.1913 0.3341
4 0.1873 0.3854
5 0.1756 0.3536
6 0.1539 0.3507
7 0.1600 0.3410
8 0.0768 0.5259
9 0.0000 1.1028
左边一列整体往下,最后落到 0(中间有两处小反弹),
右边一列最低出现在 3 次(0.3341),之后一路涨回 1.1028。
两条曲线分岔的地方,就是「开始记噪声」的地方。
真实的数据分析里没有 sin 可以对照,所以靠的是另一套办法:
留出一部分数据不看(训练/验证/测试),用没看过的数据来挑次数。
这也是第 7 章讲有监督学习时反复要用的那套流程。
[6] 「回归」这个词是怎么来的
1886 年,高尔顿量了一千多对父子的身高,画成散点图,发现一件事:
父亲很高,儿子也高,但没有父亲那么高;父亲很矮,儿子也矮,
但没那么矮。整体在往中间收。
他把这个现象叫「向平均回归」(regression toward mediocrity)。
后来的统计学家把这个词借过来,专指「用一条线去拟合条件平均」。
名字里那个「回归」早就不指身高了,可它留了下来。
顺带说一句:高尔顿当年的解释是错的。
不是「高个子的儿子会变矮」,而是身高由很多因素共同决定,
极端值必然是「很多因素同时往一个方向偏」的结果,
下一代这些因素重新抽一遍,自然就回到中间。
这叫「回归到均值」,是统计里最容易误解的一句话——
它说的是群体趋势,不是任何一个人的命运。
第一段那张表要连 t 值一起读。截距 3.0616、斜率 1.7880,真值是 3 和 1.8, 差得都不多,而且标准误很小 —— 这叫「估得准」。如果标准误很大,同样的系数就只能叫「估了一下」。 第二段是 R² 的软肋。塞一串随机数,R² 从 0.9891 涨到 0.9894。 涨得少,可它只涨不跌 —— 这个方向性是结构性的,不是这次运气好。 第三段那张两行表,是全节最该记住的。同一个变量 x1,单独放进去系数 1.7880、t 值 58.59; 再加一个几乎一样的 x2,系数变成 0.2342、t 值 0.33。R² 却几乎没变。 这一行数字把「预测」和「解释」的区别说尽了。 第四段那个 4.25e-11 不是精度问题,是数学上必然。10 个点配 10 个系数,方程组恰好有唯一解, 穿过去是能做到的。所以「训练误差为零」这件事本身不提供任何信息 —— 它只是说「参数够多」。 第五段那张表要看两列的走势,不是看具体数字。左列单调向下、右列先降后升, 这个 X 形是过拟合的标准长相,换任何数据、任何模型都会再见到它。 第六段是历史,别跳过。「回归到均值」这个说法被误用的次数, 比这一节其他所有概念加起来都多 —— 它描述群体,不预测个人。
30 秒实验
- 把第一段的
n从 40 改成 400,重跑。标准误会缩小到原来的三分之一左右(跟根号 n 成反比), 系数的估计值会更贴近真值 —— 这是「多测几个点」的收益。 - 第三段把
x2的扰动从 0.15 改成 3.0(相关性降到 0.9 左右),重跑。 共线性变弱,x1 的系数应该明显往 1.7880 回,标准误也应该降下来。 - 第五段把新点改成「训练点本身」,也就是用训练误差当判据。 你会发现 9 次永远最好 —— 这就是只看训练误差会选错模型的最小例子。
常见误区
- 以为 R² 越高模型越好。加一个纯随机列,R² 也会涨。 比模型要么用调整 R²,要么用测试集,不能只看 R² 本身。
- 以为系数大就重要、系数小就不重要。共线性下系数会乱跑, 一个 0.23 和一个 1.59 可能只是同一个 1.8 被劈成两半。看重要性要看标准化的系数, 或者看拿掉它之后 R² 掉多少。
- 以为标准误只是「误差范围」,不影响结论。标准误涨 23 倍,t 值就从 58 掉到 0.33, 同一个变量从「铁证」变成「看不出来」。它改的不是精度,是结论。
- 以为「回归到均值」是说极端会变正常。它说的是群体趋势: 极端值里「运气成分」大的那部分,下一次不会再出现。 这跟「惩罚优秀」「向平庸看齐」完全是两回事。
自测三问(点开对答案)
1. 为什么加一个纯随机特征,R² 也会涨? —— 因为 R² 的定义是 `1 − 残差平方和/总平方和`, 而**多一列自变量,残差平方和一定不会变大**(最坏情况是这列系数取 0,等于没用)。 **所以 R² 只会涨不会跌,它天然偏向复杂模型。**要修正这一点, 就得用调整 R²(按参数个数打折)或者留出测试集。 2. 共线性下 R² 还挺高,为什么说模型「废了」? —— **因为废的不是预测,是解释。**R² 高只说明「这几个变量合起来能拟合」, 可具体每一个起了多大作用,模型说不出来 —— 系数 0.2342 和 1.5853 只是 1.8 的一个随机劈法, 换个种子就变。 **而且两个 t 值都掉到不显著,明明合起来非常显著。**做决策要的是「动哪个变量有用」, 这一问被共线性毁了。 3. 训练误差降到零,为什么反而是坏消息? —— 因为**参数个数追上样本个数时,模型可以把每个点都穿过去,包括噪声点。** Demo 里 10 个点配 9 次多项式,训练误差 4.25e-11, 新点误差 1.1028 —— **它记住的是这一批数据,不是背后的规律。**判据只有一个: 拿没见过的数据去试。最小二乘对每个点一视同仁。 下一节给每个点配一个权重 —— 一个离群点、一段测不准的数据,都能靠这一个改动处理掉。
- ☐ (本节完,下一节 4.3 加权回归分析)