背景
多重共线性是回归分析中一种统计现象,指的是自变量(预测变量)之间存在较高的相关性。当多个自变量之间高度相关时,它们会携带相似的信息,从而导致模型难以区分这些变量对因变量的独立贡献
- 完美共线性:当一个特征是其他特征的完全线性组合时,称为完美共线性(极少见)
- 强共线性:当特征之间有较强但不完全的线性相关性时,称为强共线性(更常见)
多重共线性会导致:
- 不稳定的模型系数:特别是在回归模型中,某些特征的系数可能变得非常大,方向甚至会发生翻转
- 特征贡献难以解释:在高度相关的特征中,很难区分哪个特征对目标变量贡献更大
- 数值计算问题:对一些算法来说,共线性可能导致矩阵不可逆或病态,使计算过程变得不稳定
- 过拟合风险:多重共线性可能让模型捕捉到不必要的噪声
机器学习模型是否需要关注多重共线性?
主要取决于具体的模型和目标任务
对共线性敏感的模型:线性回归、逻辑回归、广义线性模型(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()
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}")
绘制气泡图可视化相关系数矩阵,并使用阈值 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)"])
计 算方差膨胀因子(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']},未发现显著的多重共线性。")
通过计算条件数判断数据集是否存在整体多重共线性,但无法具体识别哪些特征之间存在多重共线性
往期推荐
期刊配图:SHAP可视化改进依赖图+拟合线+边缘密度+分组对比
期刊配图:多种机器学习算法结合SHAP特征贡献在递归特征选择中的运用
复现SCI文章 SHAP 依赖图可视化以增强机器学习模型的可解释性
复现 Nature 图表——基于PCA的高维数据降维与可视化实践及其扩展
复现Nature图表——基于PCA降维与模型预测概率的分类效果可视化
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
个人观点,仅供参考