评估 ML 模型特征重要性的方法
背景与核心问题
在商业场景中审查机器学习模型时,最常被问到的问题是:
“影响模型预测的主要因素是什么?”
本文介绍了如何估算机器学习(ML)模型中特征的重要性,并示范了三种常用的方法:
- 内置模型特定特征重要性
- 排列和丢弃(drop)特征重要性
- 基于 SHAP 值的特征重要性
本文还包含了加载示例数据、构建模型及评估模型性能的完整代码示例。
1. 示例模型及数据加载
下面使用 scikit-learn 提供的波士顿房价数据构建一个 RandomForestRegressor
模型,该数据集源自 Kaggle 的波士顿住房数据。
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn import metrics
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor# 加载波士顿房价数据
boston = load_boston()
X = pd.DataFrame(boston.data, columns=boston.feature_names)
y = boston.target# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=22)# 构建 RandomForestRegressor 模型
model = RandomForestRegressor(n_estimators=200)
model.fit(X_train, y_train)# 使用模型预测并评估性能
y_pred = model.predict(X_test)
print('RMSE:', np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
print('R-Squared:', metrics.r2_score(y_test, y_pred))
# 输出示例:
# RMSE: 3.656865370315698
# R-Squared: 0.8405983138750325
2. 内置模型特定特征重要性
2.1 概述
对于许多模型来说,我们可以利用模型自身的属性来计算特征重要性。
-
基于树的模型
对于树模型,其特征重要性通常依据树节点在分割时的表现进行评估。
在节点分割过程中,会尝试所有特征,并选择能最大程度优化指标(如基尼系数、信息增益)的特征。常考虑的因素包括:
- 分割频率:一个特征在分割节点时被选择的次数。
- 分割收益:该特征在分割过程中带来的性能提升。
- 受影响的观测数:该节点分割影响的样本数量。
在 scikit-learn 的
RandomForestRegressor
示例中,特征重要性通过“加权(观测数)吉尼增益”进行计算。 -
回归模型
对于线性回归模型,可以用特征系数的绝对值来表示其重要性,但需注意:- 不同特征的取值范围可能不同,因此通常需要进行标准化处理。
- 如果系数的标准误差较大,则其对特征重要性的估计可能不够准确。
2.2 示例代码
使用 scikit-learn 的内置方法获取 RandomForestRegressor
模型的特征重要性示例如下:
# 根据特征重要性排序并绘制水平条形图
sorted_idx = model.feature_importances_.argsort()
plt.barh(boston.feature_names[sorted_idx],model.feature_importances_[sorted_idx]
)
plt.xlabel("RandomForestRegressor Feature Importance")
plt.show()
3. 排列和丢弃特征重要性
3.1 排列(Permutation)特征重要性
排列特征重要性的直觉如下:
- 若某特征对预测没有显著作用,则随机打乱该特征的值后,模型性能不会发生明显变化;
- 若特征重要,则打乱其值会导致模型性能大幅下降。
步骤:
- 使用已训练模型和测试数据集计算基准指标(如 R² 或 RMSE)。
- 针对测试集中的每个特征,随机排列该特征的值,然后评估模型性能。
- 特征的重要性得分定义为打乱后的性能指标与基准值之间的差异。
- 对每个特征依次重复上述步骤。
3.2 丢弃(Drop Column)特征重要性
丢弃特征重要性类似于后向特征选择,不过每次仅移除一个特征。
- 直觉:重要特征若被移除,模型性能会显著下降。
步骤:
- 利用原始数据计算模型的基准指标。
- 针对数据中的每个特征,移除该特征后重新训练模型,并评估其在测试集上的性能。
- 计算移除后的模型性能与基准指标之间的差值,作为该特征的重要性得分。
注意:由于丢弃特征重要性需要针对每个特征重新训练模型,其计算速度相对较慢,在某些实际应用中可能不够高效。
3.3 使用 rfpimp 库实现
可以借助 Python 库 rfpimp
实现上述两种方法。
排列特征重要性示例
from rfpimp import permutation_importancesperm_importance = permutation_importances(model, X_train, y_train, oob_regression_r2_score)
perm_importance.sort_values(by=['Importance']).plot.barh(y='Importance')
丢弃特征重要性示例
from rfpimp import dropcol_importances
from sklearn.metrics import r2_scoredef custom_regression_r2_score(model, X, y, sample_weights):y_pred = model.predict(X)return r2_score(y, y_pred)drop_importance = dropcol_importances(model, X_train, y_train, None, None, custom_regression_r2_score)
drop_importance.sort_values(by=['Importance']).plot.barh(y='Importance')
4. 基于 SHAP 值的特征重要性
4.1 概述
SHAP(SHapley Additive exPlanations)值用于评估各特征对单个预测结果的贡献,平均所有实例的 SHAP 值即可获得全局特征重要性。
4.2 使用 SHAP 库
-
安装 SHAP 库:
pip install shap
或在 conda 环境中:
conda install -c conda-forge shap
-
创建 SHAP 解释器并计算 SHAP 值:
import shap explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X_train) shap_imp_pd = pd.DataFrame(index=boston.feature_names, data=np.mean(np.absolute(shap_values), axis=0), columns=["Importance"] ) shap_imp_pd.sort_values(by=['Importance']).plot.barh(y='Importance')
5. 小结
特征重要性的目的是对各特征在模型中的预测能力进行全局比较。为了更准确地评估特征贡献,需要注意以下两个问题:
-
特征多重共线性
当多个特征之间存在强相关性时,采用上述方法得到的特征重要性可能不准确。 -
特征交互作用
虽然单个特征可能不明显,但多个特征组合可能具有较强的预测力。 -
方法选择建议
- 计算效率:内置方法 > 排列重要性 > SHAP > 剔除重要性
- 解释性:SHAP > 其他方法
通过结合使用内置指标、排列与丢弃以及 SHAP 值计算方法,可以全面评估模型中特征的贡献,从而支持更加科学的数据分析与决策。