多重共线性问题在机器学习中的典型场景与应对技巧

机器学习数据库算法

picture.image

背景

多重共线性是回归分析中一种统计现象,指的是自变量(预测变量)之间存在较高的相关性。当多个自变量之间高度相关时,它们会携带相似的信息,从而导致模型难以区分这些变量对因变量的独立贡献

  • 完美共线性:当一个特征是其他特征的完全线性组合时,称为完美共线性(极少见)
  • 强共线性:当特征之间有较强但不完全的线性相关性时,称为强共线性(更常见)

多重共线性会导致:

  • 不稳定的模型系数:特别是在回归模型中,某些特征的系数可能变得非常大,方向甚至会发生翻转
  • 特征贡献难以解释:在高度相关的特征中,很难区分哪个特征对目标变量贡献更大
  • 数值计算问题:对一些算法来说,共线性可能导致矩阵不可逆或病态,使计算过程变得不稳定
  • 过拟合风险:多重共线性可能让模型捕捉到不必要的噪声

机器学习模型是否需要关注多重共线性?

主要取决于具体的模型和目标任务

对共线性敏感的模型:线性回归、逻辑回归、广义线性模型(GLM)等

对共线性不敏感的模型:树模型(决策树、随机森林、梯度提升树等)、神经网络等

具体应用场景的影响:解释性任务如果需要从模型中提取特征的重要性或解释其系数(如线性回归中的系数),就必须关注多重共线性。因为高共线性会让系数变得难以解释、预测任务如果模型的目标是纯预测,而非解释,那么对于决策树等鲁棒性强的模型,共线性可能并不会显著降低性能

如何检测多重共线性?

  • 简单相关系数矩阵: 计算特征之间的相关系数,如果两个特征之间的相关系数接近±1,说明它们可能存在共线性
  • 方差膨胀因子(VIF):VIF<5多重共线性较弱、VIF>10多重共线性较强,可能需要处理
  • 特征选择的条件数:当条件数较高(如 >30)时,表明共线性较严重

应对多重共线性的方法包括删除冗余特征、正则化(如岭回归)、降维(如PCA)、或选择对共线性不敏感的模型(如树模型)

代码实现

数据读取


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt
          
plt.rcParams['font.family'] = 'Times New Roman'
          
plt.rcParams['axes.unicode_minus'] = False
          
from sklearn.model_selection import train_test_split
          
df = pd.read_excel('2025-1-5公众号Python机器学习AI.xlsx')
      

相关系数矩阵检测


          
import seaborn as sns
          

          
# 计算相关系数矩阵
          
corr = df.corr()
          

          
# 创建图形
          
fig, ax = plt.subplots(figsize=(10, 8), dpi=1200)
          
cmap = plt.cm.viridis
          
norm = plt.Normalize(vmin=-1, vmax=1)
          

          
# 初始化一个空的可绘制对象用于颜色条
          
scatter_handles = []
          

          
# 循环绘制气泡图和数值
          
for i in range(len(corr.columns)):
          
    for j in range(len(corr.columns)):
          
        if i > j:  # 对角线左下部分,只显示气泡
          
            color = cmap(norm(corr.iloc[i, j]))  # 根据相关系数获取颜色
          
            scatter = ax.scatter(i, j, s=np.abs(corr.iloc[i, j]) * 1000, color=color, alpha=0.75)
          
            scatter_handles.append(scatter)  # 保存scatter对象用于颜色条
          
        elif i < j:  # 对角线右上部分,只显示数值
          
            color = cmap(norm(corr.iloc[i, j]))  # 数值的颜色同样基于相关系数
          
            ax.text(i, j, f'{corr.iloc[i, j]:.2f}', ha='center', va='center', color=color, fontsize=10)
          
        else:  # 对角线部分,显示空白
          
            ax.scatter(i, j, s=1, color='white')
          

          
# 设置坐标轴标签
          
ax.set_xticks(range(len(corr.columns)))
          
ax.set_xticklabels(corr.columns, rotation=45, ha='right', fontsize=10)
          
ax.set_yticks(range(len(corr.columns)))
          
ax.set_yticklabels(corr.columns, fontsize=10)
          
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
          
sm.set_array([])  # 仅用于显示颜色条
          
fig.colorbar(sm, ax=ax, label='Correlation Coefficient')
          
plt.savefig("1.png", format='png', bbox_inches='tight')
          
plt.tight_layout()
          
plt.show()
      

picture.image


          
def detect_high_multicollinearity(df, threshold=0.8):
          
    # 计算相关系数矩阵
          
    corr_matrix = df.corr()
          
    
          
    # 提取上三角矩阵(排除对角线)
          
    upper_triangle = np.triu(np.ones(corr_matrix.shape), k=1)
          
    high_corr_indices = np.where(np.abs(corr_matrix.values) * upper_triangle > threshold)
          
    
          
    # 转换为特征对列表
          
    high_corr_pairs = [
          
        (df.columns[i], df.columns[j], corr_matrix.iloc[i, j])
          
        for i, j in zip(*high_corr_indices)
          
    ]
          
    
          
    return high_corr_pairs
          

          

          
# 测试函数
          
high_corr_features = detect_high_multicollinearity(df, threshold=0.8)
          

          
print("高度多重共线性的特征对及其相关系数:")
          
for pair in high_corr_features:
          
    print(f"{pair[0]} 和 {pair[1]} 的相关系数为 {pair[2]:.2f}")
      

picture.image

绘制气泡图可视化相关系数矩阵,并使用阈值 0.8检测数据集中高度多重共线性的特征对及其相关系数

方差膨胀因子(VIF)


          
from statsmodels.stats.outliers_influence import variance_inflation_factor
          
from patsy import dmatrix
          

          
def vif_analysis(df, high_threshold=10, low_threshold=5):
          
    # 确保只处理数值型特征
          
    df_numeric = df.select_dtypes(include=[np.number])
          

          
    # 添加常数项,保证VIF计算正确
          
    X = dmatrix(" + ".join(df_numeric.columns), data=df_numeric, return_type='dataframe')
          

          
    # 计算每个特征的VIF
          
    vif_data = pd.DataFrame()
          
    vif_data["Feature"] = X.columns
          
    vif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
          
    
          
    # 去掉常数项的VIF
          
    vif_data = vif_data[vif_data["Feature"] != "Intercept"]
          

          
    # 筛选出高共线性和低共线性特征
          
    high_multicollinearity = vif_data[vif_data["VIF"] > high_threshold]["Feature"].tolist()
          
    low_multicollinearity = vif_data[vif_data["VIF"] < low_threshold]["Feature"].tolist()
          
    
          
    return {
          
        "High Multicollinearity (VIF > {})".format(high_threshold): high_multicollinearity,
          
        "Low Multicollinearity (VIF < {})".format(low_threshold): low_multicollinearity
          
    }
          

          

          
# 测试函数
          
vif_results = vif_analysis(df, high_threshold=10, low_threshold=5)
          

          
print("存在高共线性的特征 (VIF > 10):", vif_results["High Multicollinearity (VIF > 10)"])
          
print("存在低共线性的特征 (VIF < 5):", vif_results["Low Multicollinearity (VIF < 5)"])
      

picture.image

计 算方差膨胀因子(VIF)筛选出具有高共线性(VIF > 10)和低共线性(VIF < 5)的特征,以帮助分析多重共线性问题

特征选择的条件数


          
def calculate_condition_number(df, threshold=30):
          
   
          
    # 确保只处理数值型特征
          
    df_numeric = df.select_dtypes(include=[np.number])
          
    
          
    # 标准化特征矩阵(均值为0,方差为1)
          
    X = (df_numeric - df_numeric.mean()) / df_numeric.std()
          
    
          
    # 计算奇异值
          
    singular_values = np.linalg.svd(X, compute_uv=False)
          
    
          
    # 计算条件数
          
    condition_number = max(singular_values) / min(singular_values)
          
    
          
    # 检查是否存在多重共线性
          
    multicollinearity = condition_number > threshold
          
    
          
    return {
          
        "Condition Number": condition_number,
          
        "Multicollinearity Detected": multicollinearity,
          
        "Threshold": threshold
          
    }
          

          

          
# 测试函数
          
condition_number_results = calculate_condition_number(df, threshold=30)
          

          
# 打印结果
          
print(f"条件数: {condition_number_results['Condition Number']:.2f}")
          
if condition_number_results["Multicollinearity Detected"]:
          
    print(f"条件数大于阈值 {condition_number_results['Threshold']},表明存在多重共线性。")
          
else:
          
    print(f"条件数小于阈值 {condition_number_results['Threshold']},未发现显著的多重共线性。")
      

picture.image

通过计算条件数判断数据集是否存在整体多重共线性,但无法具体识别哪些特征之间存在多重共线性

往期推荐

期刊配图:SHAP可视化改进依赖图+拟合线+边缘密度+分组对比

期刊配图:基于t-sne降维与模型预测概率的分类效果可视化

期刊配图:多种机器学习算法结合SHAP特征贡献在递归特征选择中的运用

置信区间+误差条:机器学习分类评价指标精美呈现

SCI图表:基于相关性和标准差的多模型评价——泰勒图解析

期刊文章配图:基于分组折线图的多机器学习模型表现评估对比

复现SCI文章 SHAP 依赖图可视化以增强机器学习模型的可解释性

SCI图表复现:优化SHAP特征贡献图展示更多模型细节

复现 Nature 图表——基于PCA的高维数据降维与可视化实践及其扩展

复现Nature图表——基于PCA降维与模型预测概率的分类效果可视化

SCI图表复现:特征相关性气泡热图展示

一图胜千言:回归预测模型训练集与测试集的进阶可视化

期刊文章配图:基于雷达图的多机器学习模型表现评估对比

期刊文章配图:斯皮尔曼相关系数热图反应非线性变量相关性

picture.image

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
相关资源
火山引擎大规模机器学习平台架构设计与应用实践
围绕数据加速、模型分布式训练框架建设、大规模异构集群调度、模型开发过程标准化等AI工程化实践,全面分享如何以开发者的极致体验为核心,进行机器学习平台的设计与实现。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论