SelectByTargetMeanPerformance#

SelectByTargetMeanPerformance() 根据性能指标选择特征,例如分类的 ROC-AUC 或准确率,或回归的均方误差和 R 平方。

性能指标是通过将预测值与目标的真实值进行比较获得的。预测值越接近真实目标值,性能指标的值就越好。通常,这些预测值是从机器学习模型中获得的。

SelectByTargetMeanPerformance() 使用一种非常简单的方法来获取“预测”。如果变量是连续的,它返回每个类别或每个区间的目标值的平均值。通过将这些“预测”值与目标值进行比较,它确定每个特征的选择性能指标的值。

程序#

这个特征选择的想法非常简单;它涉及对每个级别(类别或区间)的响应(目标)取平均值,因此相当于在单个分类变量与响应变量之间进行最小二乘拟合,连续变量中的类别由区间定义。

尽管方法简单,但它有许多优点:

  • 速度:计算均值和区间快速、直接且高效。

  • 关于特征大小的稳定性:连续变量的极端值不会像在许多模型中那样扭曲预测。

  • 连续变量与分类变量之间的可比性。

  • 不假设线性关系,因此可以识别非线性。

  • 不需要将分类变量编码为数字。

该方法也有一些局限性。首先,区间数量的选择以及阈值的设定是任意的。此外,当在评估过程中意外引入NAN时,稀有类别和非常偏斜的变量会引发错误。

SelectByTargetMeanPerformance() 与交叉验证一起工作。它使用 k-1 折来定义数值区间并学习每个类别或区间的目标均值。然后,它使用剩余的折来评估特征的性能:即在最后一折中,它将数值变量排序到区间中,用学习到的目标估计值替换区间和类别,并计算每个特征的性能。

重要#

SelectByTargetMeanPerformance() 自动识别数值变量和分类变量。它将选择分类变量为那些被转换为对象或分类类型的变量,以及数值变量为那些数值类型的变量。因此,请确保您的变量具有正确的数据类型。

故障排除#

使用此选择器时,您可能会遇到的主要问题是,在用目标均值估计替换类别或区间时,变量中引入了缺失数据。

分类变量#

当第 k 折中存在的类别在用于计算每个类别平均目标值的第 k-1 折中不存在时,分类变量中会引入 NAN。这可能是由于分类变量具有高基数(很多类别)或稀有类别,即在观察中仅占很小比例的类别。

如果发生这种情况,尝试减少变量的基数,例如通过将罕见标签分组到一个组中。查看 RareLabelEncoder 以获取更多详细信息。

数值变量#

当第k次交叉验证折叠中存在的区间在用于计算每个区间平均目标值的第k-1次折叠中不存在时,数值变量中会引入NAN。这可能是因为数值变量高度偏斜,或者具有很少的唯一值,例如,如果变量是离散的而不是连续的。

如果发生这种情况,检查有问题的变量的分布,并尝试识别问题。尝试使用等频区间而不是等宽区间,并减少箱的数量。

如果变量是离散的并且具有较少的唯一值,你可以做的是将变量转换为对象类型,这样选择器就会评估每个唯一值的平均目标值。

最后,如果一个数值变量确实是连续的且没有偏斜,检查它是否没有意外地被转换为对象类型。

示例#

让我们看看如何使用这种方法在泰坦尼克号数据集中选择变量。这个数据集包含数值变量和分类变量,因此它是展示这个选择器的一个好选项。

让我们导入所需的库和类,并准备泰坦尼克号数据集:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split

from feature_engine.datasets import load_titanic
from feature_engine.encoding import RareLabelEncoder
from feature_engine.selection import SelectByTargetMeanPerformance

data = load_titanic(
    handle_missing=True,
    predictors_only=True,
    cabin="letter_only",
)

# replace infrequent cabins by N
data['cabin'] = np.where(data['cabin'].isin(['T', 'G']), 'N', data['cabin'])

# cap maximum values
data['parch'] = np.where(data['parch']>3,3,data['parch'])
data['sibsp'] = np.where(data['sibsp']>3,3,data['sibsp'])

# cast variables as object to treat as categorical
data[['pclass','sibsp','parch']] = data[['pclass','sibsp','parch']].astype('O')

print(data.head())

我们可以看到以下数据的前5行:

  pclass  survived     sex      age sibsp parch      fare cabin embarked
0      1         1  female  29.0000     0     0  211.3375     B        S
1      1         1    male   0.9167     1     2  151.5500     C        S
2      1         0  female   2.0000     1     2  151.5500     C        S
3      1         0    male  30.0000     1     2  151.5500     C        S
4      1         0  female  25.0000     1     2  151.5500     C        S

现在让我们继续将数据分割为训练集和测试集:

# separate train and test sets
X_train, X_test, y_train, y_test = train_test_split(
    data.drop(['survived'], axis=1),
    data['survived'],
    test_size=0.1,
    random_state=0)

X_train.shape, X_test.shape

我们看到了以下数据集的大小:

((1178, 8), (131, 8))

现在,我们设置 SelectByTargetMeanPerformance() 。我们将使用3折交叉验证来检查roc-auc。我们将数值变量分离成等频区间。并且我们将保留那些roc-auc大于所有特征的平均ROC-AUC的变量(默认功能)。

sel = SelectByTargetMeanPerformance(
    variables=None,
    scoring="roc_auc",
    threshold=None,
    bins=3,
    strategy="equal_frequency",
    cv=3,
    regression=False,
)

sel.fit(X_train, y_train)

通过 fit() 方法,转换器:

  • 用目标均值替换类别

  • 将数值变量分类到等频箱中

  • 用目标均值替换箱子

  • 计算每个转换变量的roc-auc

  • 选择roc-auc大于平均值的特征

在属性 variables_ 中,我们找到了被评估的变量:

sel.variables_
['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare', 'cabin', 'embarked']

在属性 features_to_drop_ 中,我们找到未被选择的变量:

sel.features_to_drop_
['age', 'sibsp', 'parch', 'embarked']

评估特征重要性#

在属性 feature_performance_ 中,我们找到每个特征的 ROC-AUC。请记住,这是每个交叉验证折中的平均 ROC-AUC:

sel.feature_performance_

在以下输出中,我们看到了每个变量的目标均值编码返回的ROC-AUC:

{'pclass': 0.668151138112005,
'sex': 0.764831274819234,
'age': 0.535490029737471,
'sibsp': 0.5815934176199077,
'parch': 0.5721327969642238,
'fare': 0.6545985745474006,
'cabin': 0.630092526712033,
'embarked': 0.5765961846034091}

所有特征的平均 ROC-AUC 为 0.62,我们可以如下计算:

pd.Series(sel.feature_performance_).mean()

0.6229357428894605

在属性 feature_performance_std_ 中,我们找到每个特征的 ROC-AUC 的标准差:

sel.feature_performance_std_

下面我们看到 ROC-AUC 的标准差:

{'pclass': 0.0062490415569808975,
 'sex': 0.006574623168243345,
 'age': 0.023454310730681827,
 'sibsp': 0.007263903286722272,
 'parch': 0.017865107795851633,
 'fare': 0.01669212962579665,
 'cabin': 0.006868970787685758,
 'embarked': 0.008925910686325774}

我们可以将性能与标准差一起绘制,以更好地了解特征的重要性:

r = pd.concat([
    pd.Series(sel.feature_performance_),
    pd.Series(sel.feature_performance_std_)
], axis=1
)
r.columns = ['mean', 'std']

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

plt.title("Feature importance")
plt.ylabel('ROC-AUC')
plt.xlabel('Features')
plt.show()

在下图中,我们可以看到特征的重要性:

../../_images/target-mean-sel-std.png

通过这个,我们可以更好地理解特征与目标变量之间的关系,基于线性回归模型。

检查生成的数据框#

通过 transform() 我们可以继续并删除这些特征:

Xtr = sel.transform(X_test)

Xtr.head()
     pclass     sex     fare cabin
1139      3    male   7.8958     M
533       2  female  21.0000     M
459       2    male  27.0000     M
1150      3    male  14.5000     M
393       2    male  31.5000     M

最后,我们还可以获取最终转换数据中的特征名称:

sel.get_feature_names_out()
['pclass', 'sex', 'fare', 'cabin']

附加资源#

查看也:

所有笔记本都可以在 专用仓库 中找到。

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

../../_images/fsml.png

机器学习的特征选择#











或者阅读我们的书:

../../_images/fsmlbook.png

机器学习中的特征选择#















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