SelectByShuffling#

SelectByShuffling() 选择那些随机值排列会降低模型性能的特征。如果一个特征具有预测性,将其值在各行之间打乱会导致预测结果与实际结果显著偏离。相反,如果该特征不具有预测性,改变其值的顺序对模型的预测几乎没有影响。

程序#

该算法操作如下:

  1. 使用所有可用特征训练机器学习模型。

  2. 为模型建立一个基准性能指标。

  3. 在保持所有其他特征不变的情况下,打乱单个特征的值。

  4. 使用步骤1中的模型,通过打乱特征来生成预测。

  5. 基于这些新的预测来衡量模型的性能。

  6. 如果性能下降超过预定义的阈值,保留该功能。

  7. 对每个功能重复步骤3-6,直到所有功能都被评估。

Python 示例#

让我们看看如何使用 SelectByShuffling() 与 Scikit-learn 自带的糖尿病数据集。首先,我们加载数据:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from feature_engine.selection import SelectByShuffling

X, y = load_diabetes(return_X_y=True, as_frame=True)
print(X.head())

在以下输出中,我们看到了糖尿病数据集:

        age       sex       bmi        bp        s1        s2        s3  \
0  0.038076  0.050680  0.061696  0.021872 -0.044223 -0.034821 -0.043401
1 -0.001882 -0.044642 -0.051474 -0.026328 -0.008449 -0.019163  0.074412
2  0.085299  0.050680  0.044451 -0.005670 -0.045599 -0.034194 -0.032356
3 -0.089063 -0.044642 -0.011595 -0.036656  0.012191  0.024991 -0.036038
4  0.005383 -0.044642 -0.036385  0.021872  0.003935  0.015596  0.008142

         s4        s5        s6
0 -0.002592  0.019907 -0.017646
1 -0.039493 -0.068332 -0.092204
2 -0.002592  0.002861 -0.025930
3  0.034309  0.022688 -0.009362
4 -0.002592 -0.031988 -0.046641

现在,我们设置一个机器学习模型。我们将使用线性回归:

linear_model = LinearRegression()

现在,我们设置 SelectByShuffling() 通过打乱来选择特征。我们将使用3折交叉验证来检查 r2 的变化。

参数 threshold 被保留为 None,这意味着如果性能下降大于所有特征引起的平均下降,则会选择特征。

tr = SelectByShuffling(
    estimator=linear_model,
    scoring="r2",
    cv=3,
    random_state=0,
)

fit`() 方法识别重要变量——那些值的排列会导致模型性能下降的变量。`transform() 方法随后从数据集中移除这些变量。

Xt = tr.fit_transform(X, y)

SelectByShuffling() 存储了使用所有特征训练的模型的性能在其属性中:

tr.initial_model_performance_

在以下输出中,我们看到了在整个数据集上训练和评估的线性回归的 r2,没有进行洗牌,使用了交叉验证。

0.488702767247119

在以下部分中,我们将探讨 SelectByShuffling() 存储的一些额外有用的数据。

评估特征重要性#

SelectByShuffling() 存储了通过打乱每个特征引起的模型性能变化。

tr.performance_drifts_

在以下输出中,我们可以看到在打乱每个特征后线性回归r2的变化:

{'age': -0.0054698043007869734,
 'sex': 0.03325633986510784,
 'bmi': 0.184158237207512,
 'bp': 0.10089894421748086,
 's1': 0.49324432634948095,
 's2': 0.21163252880660438,
 's3': 0.02006839198785859,
 's4': 0.011098050006761673,
 's5': 0.4828781996541602,
 's6': 0.003963360084439538}

SelectByShuffling() 存储了性能变化的标准差:

tr.performance_drifts_std_

在以下输出中,我们看到了特征洗牌后r2变化的多样性:

{'age': 0.012788500580799392,
 'sex': 0.040792331972680645,
 'bmi': 0.042212436355346106,
 'bp': 0.05397012536801143,
 's1': 0.35198797776358015,
 's2': 0.167636042355086,
 's3': 0.03455158514716544,
 's4': 0.007755675852874145,
 's5': 0.1449579162698361,
 's6': 0.011193022434166025}

我们可以将性能变化与标准差一起绘制,以更好地了解特征洗牌如何影响模型性能:

r = pd.concat([
    pd.Series(tr.performance_drifts_),
    pd.Series(tr.performance_drifts_std_)
], axis=1
)
r.columns = ['mean', 'std']

r['mean'].plot.bar(yerr=[r['std'], r['std']], subplots=True)

plt.title("Performance drift elicited by shuffling a feature")
plt.ylabel('Mean performance drift')
plt.xlabel('Features')
plt.show()

在下图中,我们看到了通过打乱每个特征所导致的性能变化:

../../_images/shuffle-features-std.png

通过此设置,导致平均性能下降大于所有特征的平均性能的特征将被移除。如果由于任何原因,此阈值过于保守或过于宽松,通过分析之前的条形图,您可以更好地了解这些特征如何影响模型的预测,并选择不同的阈值。

检查已淘汰的功能#

SelectByShuffling() 存储了基于某个阈值将被丢弃的特征:

tr.features_to_drop_

以下特性被认为不重要,因为它们的表现漂移大于所有特性的平均表现漂移:

['age', 'sex', 'bp', 's3', 's4', 's6']

如果我们现在打印转换后的数据,我们可以看到上述特征已被移除。

print(Xt.head())

在以下输出中,我们看到了包含所选特征的数据框:

        bmi        s1        s2        s5
0  0.061696 -0.044223 -0.034821  0.019907
1 -0.051474 -0.008449 -0.019163 -0.068332
2  0.044451 -0.045599 -0.034194  0.002861
3 -0.011595  0.012191  0.024991  0.022688
4 -0.036385  0.003935  0.015596 -0.031988

其他资源#

有关此功能选择方法及其他方法的更多详细信息,请查看以下资源:

../../_images/fsml.png

机器学习的特征选择#











或者阅读我们的书:

../../_images/fsmlbook.png

机器学习中的特征选择#















我们的书籍和课程都适合初学者和更高级的数据科学家。通过购买它们,您正在支持 Feature-engine 的主要开发者 Sole。