4.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
即使重要性值的范围差异很大,不同指标的特征排名也大致相同。但是,这不能保证,不同的指标可能会导致显著不同的特征重要性,特别是对于针对不平衡分类问题训练的模型,对于这些模型,分类指标的选择至关重要。
4.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}\]
4.2.2. 与树中基于杂质的重要性之间的关系#
基于树的模型提供了另一种 基于杂质平均减少的特征重要性(MDI)度量。杂质由决策树的分割标准(基尼、对数损失或均方误差)量化。但是,当模型过拟合时,这种方法可能会赋予可能在未见数据上不可预测的特征很高的重要性。另一方面,基于排列的特征重要性避免了这个问题,因为它可以在未见数据上计算。
此外,树的基于杂质的特征重要性存在严重偏差,并且偏向高基数特征(通常是数值特征),而不是低基数特征,例如二元特征或具有少量可能类别的分类变量。
基于排列的特征重要性不会表现出这种偏差。此外,排列特征重要性可以使用模型预测的任何性能指标计算,并且可以用于分析任何模型类别(不仅仅是基于树的模型)。
以下示例突出了基于杂质的特征重要性与基于排列的特征重要性之间的局限性:排列重要性与随机森林特征重要性(MDI)。