5.2. 排列特征重要性#
排列特征重要性是一种模型检查技术,用于衡量每个特征对给定表格数据集上已拟合模型的统计性能的贡献。该技术对于非线性或不透明的估计器特别有用,它通过随机打乱单个特征的值并观察模型得分的退化来工作[1]。通过打破特征与目标之间的关系,我们能确定模型对特定特征的依赖程度。
在下图中,我们观察排列特征对特征与目标之间相关性的影响,进而观察对模型统计性能的影响。


在上图中,我们观察到排列一个预测性特征会破坏该特征与目标之间的相关性,从而导致模型统计性能下降。在下图中,我们观察到排列一个非预测性特征并不会显著降低模型的统计性能。
排列特征重要性一个关键优势是它与模型无关,即可以应用于任何已拟合的估计器。此外,它可以对特征进行不同排列多次计算,进一步提供了针对特定训练模型的估计特征重要性方差的度量。
下图展示了在泰坦尼克号数据集的增强版本上训练的RandomForestClassifier
的排列特征重要性,该增强版本包含random_cat
和random_num
特征,即与目标变量没有任何关联的分类特征和数值特征。

警告
被认为对差模型不重要的特征(交叉验证得分低)可能对好模型非常重要。因此,在计算重要性之前,始终重要的是使用保留集(或更好地使用交叉验证)来评估模型的预测能力。排列重要性本身并不反映特征的内在预测价值,而是反映此特征对特定模型的重要性。
函数permutation_importance
计算给定数据集上估计器的特征重要性。n_repeats
参数设置了特征随机打乱的次数,并返回特征重要性的样本。
让我们考虑以下已训练的回归模型
>>> from sklearn.datasets import load_diabetes
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.linear_model import Ridge
>>> diabetes = load_diabetes()
>>> X_train, X_val, y_train, y_val = train_test_split(
... diabetes.data, diabetes.target, random_state=0)
...
>>> model = Ridge(alpha=1e-2).fit(X_train, y_train)
>>> model.score(X_val, y_val)
0.356...
其验证性能,通过\(R^2\)分数衡量,显著高于随机水平。这使得可以使用permutation_importance
函数来探测哪些特征最具预测性。
>>> from sklearn.inspection import permutation_importance
>>> r = permutation_importance(model, X_val, y_val,
... n_repeats=30,
... random_state=0)
...
>>> for i in r.importances_mean.argsort()[::-1]:
... if r.importances_mean[i] - 2 * r.importances_std[i] > 0:
... print(f"{diabetes.feature_names[i]:<8}"
... f"{r.importances_mean[i]:.3f}"
... f" +/- {r.importances_std[i]:.3f}")
...
s5 0.204 +/- 0.050
bmi 0.176 +/- 0.048
bp 0.088 +/- 0.033
sex 0.056 +/- 0.023
请注意,顶部特征的重要性值占参考得分0.356的很大一部分。
排列重要性可以在训练集或保留的测试集或验证集上计算。使用保留集可以突出哪些特征对被检查模型的泛化能力贡献最大。在训练集上重要但在保留集上不重要的特征可能导致模型过拟合。
排列特征重要性取决于使用scoring
参数指定的评分函数。此参数接受多个评分器,这比依次使用不同的评分器多次调用permutation_importance
在计算上更高效,因为它重用了模型预测。
使用多个评分器计算排列特征重要性的示例#
在下面的示例中,我们使用了一个指标列表,但正如使用多指标评估中所述,还有更多输入格式可用。
>>> scoring = ['r2', 'neg_mean_absolute_percentage_error', 'neg_mean_squared_error']
>>> r_multi = permutation_importance(
... model, X_val, y_val, n_repeats=30, random_state=0, scoring=scoring)
...
>>> for metric in r_multi:
... print(f"{metric}")
... r = r_multi[metric]
... for i in r.importances_mean.argsort()[::-1]:
... if r.importances_mean[i] - 2 * r.importances_std[i] > 0:
... print(f" {diabetes.feature_names[i]:<8}"
... f"{r.importances_mean[i]:.3f}"
... f" +/- {r.importances_std[i]:.3f}")
...
r2
s5 0.204 +/- 0.050
bmi 0.176 +/- 0.048
bp 0.088 +/- 0.033
sex 0.056 +/- 0.023
neg_mean_absolute_percentage_error
s5 0.081 +/- 0.020
bmi 0.064 +/- 0.015
bp 0.029 +/- 0.010
neg_mean_squared_error
s5 1013.866 +/- 246.445
bmi 872.726 +/- 240.298
bp 438.663 +/- 163.022
sex 277.376 +/- 115.123
即使重要性值的尺度差异很大,不同指标的特征排名也大致相同。然而,这并非完全保证,不同的指标可能导致特征重要性显著不同,特别是对于为不平衡分类问题训练的模型,对于这些问题,分类指标的选择至关重要。
5.2.1. 排列重要性算法概述#
输入:已拟合的预测模型\(m\),表格数据集(训练或验证)\(D\)。
计算模型\(m\)在数据\(D\)上的参考分数\(s\)(例如分类器的准确率或回归器的\(R^2\))。
对于每个特征\(j\)(\(D\)的列)
对于\({1, ..., K}\)中的每次重复\(k\)
随机打乱数据集\(D\)的列\(j\),生成一个名为\(\tilde{D}_{k,j}\)的损坏数据版本。
计算模型\(m\)在损坏数据\(\tilde{D}_{k,j}\)上的分数\(s_{k,j}\)。
计算特征\(f_j\)的重要性\(i_j\),定义为
\[i_j = s - \frac{1}{K} \sum_{k=1}^{K} s_{k,j}\]
5.2.2. 与基于杂质的树模型重要性之间的关系#
基于树的模型提供了一种替代的特征重要性度量方法,即基于杂质平均减少量(MDI)的特征重要性。杂质由决策树的划分标准(Gini、对数损失或均方误差)量化。然而,当模型过拟合时,此方法可能会赋予在未见数据上不具预测性的特征高重要性。另一方面,基于排列的特征重要性可以避免这个问题,因为它可以在未见数据上计算。
此外,基于杂质的树模型特征重要性偏差较大,并且偏爱高基数特征(通常是数值特征),而不是低基数特征,例如二元特征或具有少量可能类别的分类变量。
基于排列的特征重要性不显示这种偏差。此外,排列特征重要性可以使用模型预测的任何性能指标进行计算,并且可以用于分析任何模型类别(不限于基于树的模型)。
以下示例强调了基于杂质的特征重要性与基于排列的特征重要性相比的局限性:排列重要性 vs 随机森林特征重要性 (MDI)。