用numpy.linalg.cond快速判断设计矩阵是否病态:先中心化(减均值)但不标准化,显式添加截距列后计算条件数,>30需警惕,>100通常存在强多重共线性。

怎么用 numpy.linalg.cond 快速判断设计矩阵是否病态
多重共线性本质是特征之间高度线性相关,导致设计矩阵 X 的列空间接近退化,其条件数(condition number)会显著增大。直接计算 numpy.linalg.cond 是最轻量的初筛方式:
- 先对特征做中心化(减均值),但**不要标准化**——标准化会人为改变原始尺度关系,干扰条件数解读
- 用
np.linalg.cond(X_centered),结果 > 30 值得警惕,> 100 通常表明存在强共线性 - 注意:该方法对截距项敏感,若模型含常数项(如用
sklearn.linear_model.LinearRegression(fit_intercept=True)),应在X中显式添加全 1 列后再算条件数,否则漏判截距与其他变量的共线性
为什么 statsmodels.stats.outliers_influence.variance_inflation_factor 更实用
Scikit-learn 本身不提供 VIF 计算,但 statsmodels 的 variance_inflation_factor 函数能逐个输出每个特征的 VIF 值,解释性强、阈值明确(VIF > 5 或 10 表示该特征受其他特征严重干扰):
- 必须传入 **不含截距列** 的原始
X(即只传pd.DataFrame或np.ndarray的特征部分) - 调用时循环遍历列索引:
vif = [variance_inflation_factor(X, i) for i in range(X.shape[1])] - 若某列含全零或方差为零,会抛出
LinAlgError,需提前用X.nunique() == 1或X.std() == 0过滤掉常量特征 - VIF 对缺失值敏感,输入前务必确认
X无NaN,否则结果不可信
用 sklearn.covariance.LedoitWolf 替代普通协方差矩阵做稳定性诊断
当样本量 n 接近或小于特征数 p 时,传统协方差矩阵 np.cov(X.T) 会严重失真,导致相关系数矩阵、特征值分析失效。此时可用 LedoitWolf 提供的收缩估计:
- 它自动调节协方差矩阵的“噪声水平”,比
np.cov更鲁棒,尤其适合小样本高维场景 - 计算收缩后的相关矩阵:
lw = LedoitWolf().fit(X); corr_shrunk = np.corrcoef(lw.covariance_.T) - 再检查该相关矩阵的最大特征值与最小特征值之比——若远大于 100,说明仍存在结构共线性;该比值比原始
np.corrcoef(X.T)更可信 - 注意:此方法不能替代 VIF,而是补充——VIF 检测的是回归设定下的共线性,而收缩协方差反映的是数据本身的线性依赖结构
哪些操作会让共线性检测结果失真
实际建模中几个高频误操作会掩盖或夸大共线性信号:
立即学习“Python免费学习笔记(深入)”;
- 在计算 VIF 前对
X做了StandardScaler——VIF 定义基于原始尺度,缩放后数值失去可比性,VIF 值会系统性偏低 - 用训练集算出的 VIF 直接删特征,却在测试集上重新拟合模型——未同步处理测试集特征子集,导致维度不匹配报错
ValueError: X has 5 features, but LinearRegression is expecting 3 features - 忽略分类变量的独热编码(one-hot)陷阱:对有
k类别的变量生成k个哑变量,未删去基准类,必然引入完全共线性(sum(哑变量) == 1),此时 VIF 会爆表,必须先 drop 一列
共线性不是非黑即白的开关,而是一个连续谱;真正麻烦的往往不是高 VIF 本身,而是它背后暴露的业务逻辑重叠——比如“月收入”和“年收入”同时入模,这种冗余比数学上的条件数更值得人工干预。


















