vif是衡量多元回归中自变量间多重共线性程度的指标,计算公式为$vif = \frac{1}{1-r^2}$,其中$r^2$是该自变量对其他自变量回归的决定系数;$r^2$越接近1,vif越大,共线性越严重,通常vif≥10表明存在严重多重共线性。

什么是VIF,为什么它能检测共线性
方差膨胀因子(VIF)衡量的是某个特征在以其余特征为自变量做线性回归时的决定系数 R² 的函数:VIF = 1 / (1 - R²)。
当某特征与其他特征高度相关时,R² 接近 1,VIF 就会急剧上升——通常认为 VIF > 5 或 VIF > 10 表示存在较强共线性。
Scikit-learn 本身不提供直接计算 VIF 的函数,这点容易被误以为有现成接口。必须手动对每个特征拟合一个线性回归模型(用其他特征预测它),再从 R² 推出 VIF。
用 statsmodels 计算 VIF(最稳妥的方案)
虽然问题提到 scikit-learn,但实际工程中更推荐用 statsmodels,因为它的 variance_inflation_factor 函数封装完整、数值稳定,且自动处理常数项。
- 确保输入是
numpy.ndarray或pandas.DataFrame,不含缺失值(NaN) - 若用
DataFrame,列名不能含空格或特殊符号,否则statsmodels内部可能报错ValueError: invalid literal for int() - 需显式添加截距项(
add_constant),否则 VIF 计算逻辑不成立
import pandas as pd import numpy as np from statsmodels.stats.outliers_influence import variance_inflation_factor from statsmodels.tools.tools import add_constant <h1>假设 X 是你的特征矩阵(DataFrame,无目标变量)</h1><p>X_const = add_constant(X) # 添加常数列,用于回归截距 vif_data = pd.DataFrame() vif_data["feature"] = X.columns vif_data["VIF"] = [variance_inflation_factor(X_const.values, i + 1) for i in range(len(X.columns))]</p>
注意:索引 i + 1 是因为 add_constant 把常数加在第 0 列,所以原特征从索引 1 开始。
用 scikit-learn 手动实现 VIF(仅限学习或受限环境)
如果你硬要只用 scikit-learn(比如部署环境禁装 statsmodels),就得自己循环拟合 LinearRegression:
- 每次把一个特征作为
y,其余特征作为X_train - 必须确保每次训练前都调用
.fit(),否则.score()返回未拟合状态下的默认值(可能为负或异常高) -
.score()返回的是R²,不是均方误差,别误用mean_squared_error - 特征缩放(如
StandardScaler)对 VIF 没有影响,因为 VIF 是纯线性相关性的度量,与量纲无关;但若数据含极端离群值,未缩放可能导致回归数值不稳定
from sklearn.linear_model import LinearRegression from sklearn.preprocessing import StandardScaler <p>vif_list = [] for i in range(X.shape[1]): y = X.iloc[:, i] X_others = X.iloc[:, np.arange(X.shape[1]) != i] reg = LinearRegression().fit(X_others, y) r2 = reg.score(X_others, y) vif = 1 / (1 - r2) if r2 </p>
VIF 计算中的典型错误和边界情况
-
LinAlgError: Singular matrix:说明某组“其余特征”已完全线性相关(比如两列完全相同,或一列是另一列的倍数),此时 LinearRegression 拟合失败。应在计算前先检查 np.linalg.matrix_rank(X) 是否等于列数
-
VIF = inf 或极大值(如 1e16):不是代码 bug,而是数学上确认存在完全共线性。这时候删掉冗余特征比强行压低 VIF 更合理
- 分类变量未正确编码:如果原始数据含
object 类型列(如字符串类别),必须先用 pd.get_dummies() 或 OneHotEncoder 转为数值,否则 VIF 无法计算
- 时间序列或面板数据:VIF 只反映截面相关性,不处理自相关或组内相关。此时即使 VIF 正常,模型仍可能因结构共线性失效
LinAlgError: Singular matrix:说明某组“其余特征”已完全线性相关(比如两列完全相同,或一列是另一列的倍数),此时 LinearRegression 拟合失败。应在计算前先检查 np.linalg.matrix_rank(X) 是否等于列数VIF = inf 或极大值(如 1e16):不是代码 bug,而是数学上确认存在完全共线性。这时候删掉冗余特征比强行压低 VIF 更合理object 类型列(如字符串类别),必须先用 pd.get_dummies() 或 OneHotEncoder 转为数值,否则 VIF 无法计算VIF 本身不解决共线性,只暴露它;真正要行动时,得结合业务含义判断删哪个特征,而不是机械地砍掉 VIF 最高的那个。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











