VIF是方差膨胀因子,用于量化特征间多重共线性程度,计算公式为1/(1−R²ⱼ),R²ⱼ越高说明该特征越易被其余特征线性表达,VIF>5或>10即提示中度至严重共线性。

什么是VIF,以及它为什么能反映多重共线性
VIF(Variance Inflation Factor)本质是某个特征对其余特征做线性回归时的 1 / (1 - R²)。R² 越高,说明该特征越容易被其他特征线性表达,共线性越强;VIF > 5 或 > 10(常见阈值)就提示需要警惕。
注意:VIF 对缺失值敏感,且要求所有特征为数值型。类别型变量必须先做独热编码(pd.get_dummies),但要注意避免“虚拟变量陷阱”——比如对有 3 类的变量生成 2 个 dummy 列,而不是 3 个。
用 statsmodels 计算单个特征的 VIF
statsmodels 提供了 variance_inflation_factor 函数,但它只接受二维数组和列索引,不支持 DataFrame 直接传入列名。常见错误是传错 exog(设计矩阵)或索引越界。
- 确保输入
exog是不含截距项的纯特征矩阵(add_constant=False) - 列顺序必须和原始 DataFrame 一致,索引从 0 开始 —— 比如想算
"age"的 VIF,得先用df.columns.get_loc("age")找到位置 - 若某列是常数(全相同值),R²=0,VIF 会变成 1;但若该列标准差为 0,
LinearRegression可能报LinAlgError,需提前过滤掉
from statsmodels.stats.outliers_influence import variance_inflation_factor import pandas as pd <h1>假设 df_numeric 是清洗后的数值型特征 DataFrame</h1><p>vif_data = pd.DataFrame() vif_data["feature"] = df_numeric.columns vif_data["VIF"] = [variance_inflation_factor(df_numeric.values, i) for i in range(len(df_numeric.columns))]
批量计算 VIF 并自动剔除高共线性特征
手动逐个看 VIF 值效率低,更实用的是迭代剔除最高 VIF 的特征,直到全部 ≤ 阈值(如 5)。但要注意:剔除后其余特征的 VIF 会变化,不能只筛一遍。
立即学习“Python免费学习笔记(深入)”;
- 每次剔除后必须重新计算全部剩余特征的 VIF —— 否则可能漏掉新暴露出来的共线性
- 不要直接删
df.drop(columns=[...])后继续用原 DataFrame 算,要基于当前子集重新构造exog - 若多个特征 VIF 都 > 10,优先删业务解释性弱、或与其他特征相关系数绝对值更高的那个,而非单纯看 VIF 数值大小
- 标准化(
StandardScaler)不影响 VIF 计算结果,因为 VIF 基于 R²,而 R² 对线性变换不变
scikit-learn 中没有内置 VIF,别白找
sklearn 的 LinearRegression、FeatureSelection 模块都不提供 VIF。有人试图用 sklearn.metrics.r2_score 自己实现,但容易忽略:回归目标必须是当前列,其余列为预测变量,且不能含截距(否则 R² 定义不同,VIF 失效)。
真正省事的做法是坚持用 statsmodels.stats.outliers_influence.variance_inflation_factor,它底层就是调用 OLS,逻辑严谨。如果项目已重度依赖 sklearn 流水线,可在预处理阶段单独加一步 VIF 清洗,输出干净特征再进 pipeline。
最易被忽略的一点:VIF 只检测线性共线性。两个特征呈强二次关系(如 x 和 x²)时,VIF 可能正常,但模型仍不稳定 —— 这时候得结合散点图、条件数(np.linalg.cond)或 PCA 方差解释比来辅助判断。


















