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\)的列)
对于每次重复\(k\)属于\({1, ..., 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)。