4、多元线性回归:模型扩展、矩阵形式、多重共线性问题
好,咱们进入多元线性回归。说实话,一元回归就像用一把尺子量世界——太局限了。现实中的问题,哪个不是多个因素共同作用的结果?房价不只看面积,还看地段、楼层、房龄;销售额不只看广告,还看价格、竞品、季节。所以,多元回归才是真正上战场用的家伙。
4.1 从一元到多元:模型扩展
一元线性回归的公式是:
y = β₀ + β₁x + ε
扩展到多元,其实就是加项:
y = β₀ + β₁x₁ + β₂x₂ + ... + βₚxₚ + ε
每个 xⱼ 代表一个特征,每个 βⱼ 代表这个特征对 y 的边际影响。说白了,就是「在其他条件不变的情况下,xⱼ 每变化一个单位,y 平均变化 βⱼ 个单位」。
我在项目中遇到过一个问题:客户想预测用户留存率,一开始只用了「使用时长」一个变量,R² 只有 0.3。后来加入了「登录频率」、「好友数量」、「付费金额」三个特征,R² 直接跳到 0.78。你看,多一个维度,模型就多一分解释力。
4.2 矩阵形式:优雅的数学表达
当变量多起来,写 β₀ + β₁x₁ + β₂x₂ + ... 实在太啰嗦。数学家用矩阵来搞定:
y = Xβ + ε
其中:
- y:n×1 的观测值向量
- X:n×(p+1) 的设计矩阵(第一列全是 1,对应截距项)
- β:(p+1)×1 的系数向量
- ε:n×1 的误差向量
嗯,这里要注意:设计矩阵 X 的每一行是一个样本,每一列是一个特征。第一列全为 1 是为了把截距 β₀ 也纳入矩阵运算。
那么,最小二乘法的解用矩阵怎么写?
β̂ = (XᵀX)⁻¹Xᵀy
这个公式漂亮吧?一行搞定所有系数的估计。我当年第一次看到这个公式时,觉得数学真是优雅到极致。但别高兴太早——这个公式能算的前提是 XᵀX 可逆。什么时候不可逆?这就是下面要说的核心问题。
beta = np.linalg.inv(X.T @ X) @ X.T @ y。但实际项目中我建议用 np.linalg.lstsq 或 sklearn 的 LinearRegression,数值稳定性更好。
4.3 多重共线性:隐藏的陷阱
多重共线性,说白了就是特征之间高度相关。比如预测房价时,同时用了「房屋面积」和「房间数量」——这两个变量本身就强相关,大房子房间自然多。你想想看,模型怎么区分到底是面积在起作用,还是房间数在起作用?
我曾经在一个电商项目中踩过这个坑。当时用了「浏览时长」和「页面深度」两个特征去预测转化率,结果两个系数的 p 值都大于 0.05,但联合 F 检验却显著。折腾了两天,才发现这两个特征相关系数高达 0.92。去掉其中一个后,模型瞬间清爽了。
4.3.1 怎么发现多重共线性?
我常用的方法有三个:
- 相关系数矩阵:两两特征算 Pearson 相关系数,超过 0.8 就要警惕。
- VIF(方差膨胀因子):这是最靠谱的指标。VIF > 10 说明存在严重共线性,> 5 就要注意。
- 特征值分析:XᵀX 的特征值如果接近 0,说明矩阵接近奇异,共线性严重。
VIF 的计算其实很简单:对每个特征 xⱼ,用其他所有特征去拟合它,得到 R²ⱼ,然后:
VIFⱼ = 1 / (1 - R²ⱼ)
如果 R²ⱼ 接近 1,VIF 就爆炸。举个例子:
| 特征 | R² | VIF | 结论 |
|---|---|---|---|
| 面积 | 0.85 | 6.67 | 中等共线性 |
| 房间数 | 0.92 | 12.50 | 严重共线性 |
| 楼层 | 0.12 | 1.14 | 没问题 |
4.3.2 多重共线性有什么后果?
你可能会想:「相关就相关呗,模型照样能跑啊。」没错,模型能跑,但后果很严重:
- 系数估计不稳定:数据稍微变一点,系数就大幅波动。我见过一个模型,加一条数据,某个系数从 5 变成 -3,完全没法解释。
- 标准误变大:导致 t 统计量变小,本来显著的变量变得不显著。
- 系数符号反常:理论上应该是正相关的变量,系数却变成负的。这会让业务方完全无法接受。
4.3.3 怎么处理?
我一般按这个顺序尝试:
- 删除高度相关的特征:最简单粗暴,保留业务上更重要的那个。
- 主成分分析(PCA):把相关特征合成几个不相关的主成分,但会损失可解释性。
- 岭回归(Ridge Regression):在损失函数中加入 L2 正则化,让系数收缩。这是我最常用的方法。
- 收集更多数据:有时候共线性只是因为样本量太小,数据多了自然就缓解了。
举个例子,用 Python 做岭回归:
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
# 标准化很重要!岭回归对尺度敏感
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# alpha 是正则化强度,越大系数收缩越厉害
ridge = Ridge(alpha=1.0)
ridge.fit(X_scaled, y)
print('系数:', ridge.coef_)
print('截距:', ridge.intercept_)
RidgeCV 可以自动帮你做这件事。
4.4 小结
多元线性回归是回归分析的核心武器。矩阵形式让数学表达变得简洁优雅,但多重共线性是绕不开的坑。我个人习惯是:建模前先算 VIF,发现共线性就用岭回归兜底。记住一句话——模型可以复杂,但思路必须清晰。下一章咱们聊聊模型诊断,看看怎么判断你的回归模型到底靠不靠谱。
公众号:蓝海资料掘金营,微信deep3321