Python中机器学习的特征选择工具

摘要: 还在为特征选择抓狂?这个工具了解一下!

特征选择,即在数据集中查找和选择最有用的特征的过程,是机器学习的关键步骤。不必要的特征会降低训练速度、模型的可解释性,最重要的是会降低测试集的泛化性能。

我对临时的特征选择方法感到很失望,但是在解决机器学习问题时又反复用到了这些方法,所以就创建了一个关于特征选择的Python类,该类可以在GitHub上找到。FeatureSelector类包括一些最常见的特征选择方法:
1.高百分比的缺失值特征选择法

2.共线(高度相关)特征选择法

3.树型结构模型中的零重要性特征选择法

4.低重要性特征选择法

5.唯一值特征选择法

在本文中,我将对机器学习数据集的示例使用FeatureSelector类。也会介绍该类是如何让我们快速地实现特征选择方法。

完整的代码可以在GitHub上找到,特征选择器还是一个半成品,会根据社区的需求继续改进!

示例数据集

示例中使用的是Kaggle上家庭信用违约风险机器学习竞赛的数据样本。整个数据集可以下载,演示样本如下:

该数据样本来自一个有监督分类问题,也是一个很好的数据集。因为它有许多缺失值、高度相关(共线)的特征以及对机器学习模型无用的不相关特征。

创建一个实例

创建FeatureSelector类的实例需传入结构化的数据集,该数据集行为观察值、列为特征。该类内有一些只需传入特征的方法,但是这些基于特征重要性的方法需传入训练标签。所以当用这些方法解决一个有监督分类问题时,需传入一组特征和一组标签。
from feature_selector import FeatureSelector
# Features are in train and labels are in train_labels
fs = FeatureSelector(data = train, labels = train_labels)

方法

特征选择器有5种查找要删除特征的方法,找到被标识的特征并手动地将它们从数据中删除,或者使用特征选择器中的remove函数。

下面将详细介绍每一种方法,并展示5种方法是如何同时运行的。FeatureSelector类内还有一些具有绘图功能的方法,因为检验直观的图像数据也是机器学习的一个重要组成部分。

缺失值

缺失值特征选择法比较简单:所查找的特征是超过指定阈值的缺失值。下面的调用所标识的特征都是超过60%的缺失值(粗体为输出)。
fs.identify_missing(missing_threshold = 0.6)
17 features with greater than 0.60 missing values.

按列显示缺失值的dataframe:
fs.missing_stats.head()

通过FeatureSelector类的ops属性可以查看要删除特征。具体过程如下面所列的Python 命令所示:
missing_features = fs.ops['missing']
missing_features[:5]
['OWN_CAR_AGE',
'YEARS_BUILD_AVG',
'COMMONAREA_AVG',
'FLOORSMIN_AVG',
'LIVINGAPARTMENTS_AVG']

下面是缺失值占特征比例的分布图:
fs.plot_missing()

共线特征

共线特征是高度相关的特征。在机器学习中,由于共线特征的高方差和低模型可解释性,会导致测试集的泛化性能下降。

identify_collinear方法根据指定的相关系数值查找共线特征,将相关特征对中的一个标识为要删除特征(因为只需要删除一个):

fs.identify_collinear(correlation_threshold = 0.98)
21 features with a correlation magnitude greater than 0.98.

下面是基于相关性的热度图,该图显示了相关性超过阈值的所有特征:
fs.plot_collinear()

类似的,也可以列出要删除的共线特征,或者查看共线特征的dataframe。
# list of collinear features to remove
collinear_features = fs.ops['collinear']
# dataframe of collinear features

fs.record_collinear.head()

如果想深入研究数据集,还可以传入plot_all = True给调用,绘制所有数据相关性的图表:

零重要性特征

前两种方法可以应用于任何结构化的数据集,且具有确定性——对于给定的阈值,每次结果都是相同的。但是零重要性特征选择法只针对有监督的机器学习问题(有训练模型的标签),且具有不确定性。identify_zero_important函数根据梯度提升机(GBM)学习模型来查找零重要性特征。

通过基于树型结构的机器学习模型,例如boosting集成算法,可以发现特征的重要性。重要性的相对值可以确定任务的最相关特征,绝对值就没有那么重要了,但是可以通过删除零重要性特征可以进行特征选择。零重要性特征不能作为树型模型中的节点,因此可以在不影响模型性能的情况下删除它们。

FeatureSelector通过LightGBM库的梯度提升机来查找特征重要性。为了减少差异,对特征重要性进行平均超过10次的GBM训练。此外,通过使用验证集(可关闭)进行早期停止来训练模型,以防止对训练数据的过度拟合。

下面的代码调用了该方法并提取了零重要性特征:
# Pass in the appropriate parameters
fs.identify_zero_importance(task = 'classification',
eval_metric = 'auc',
n_iterations = 10,
early_stopping = True)
# list of zero importance features
zero_importance_features = fs.ops['zero_importance']
63 features with zero importance after one-hot encoding.

传入的参数如下:

task:根据问题对应选择“classification”或“regression”

eval_metric:衡量早期停止(若禁用了早期停止,则没有必要)

n_iteration:训练次数

early_stopping:是否使用早期停止来训练模型

下面两个图由plot_feature_importances函数得出:
# plot the feature importances

fs.plot_feature_importances(threshold = 0.99, plot_n = 12)

左边是关于plot_n最重要特征的图(根据归一化的重要性所绘制,总和为1)。右边是累积重要性与特征数量的关系图。垂线画在累积重要性达到的阈值处,本例中阈值为99%。

基于重要性的方法需要记住两个要点:

(1)训练梯度提升机是随机的,每一次模型运行,特征重要性都将会改变。

这不会产生重大的影响(最重要的特征不会突然变成最少),但是它会改变某些特征的顺序,还会影响被标识的零重要性特征的数量。如果特征重要性每次都发生变化,不要感到惊讶!

(2)为了对机器学习模型进行训练,首先需要对特征进行独热编码。所以一些被标识为零重要性的特征可能是在建模过程中添加的独热编码特征。

在删除特征时可以删除任何添加的独热编码特征。但是,如果在特征选择之后要进行机器学习,则不能删除!

低重要性特征

这种方法构建立在零重要性函数的基础上,再利用模型中的特征重要性进行进一步的选择。由函数identify_low_importance可知,低重要性特征并不影响某些指定的总重要性。

例如,下面的调用显示:在实现99%的总重要性时,最低重要性特征并不是必需的。
fs.identify_low_importance(cumulative_importance = 0.99)

由上面累积重要性的图,以及低重要性不影响某些指定的总重要性这一信息可知,梯度提升机中有许多与学习无关的特征。同样,低重要性特征选择法的结果在每次训练中都会发生变化。

查看所有的特征重要性:

low_importance方法借鉴了使用主成分分析(PCA)的方法,只要求主成分所占的比例要维持在一定的百分比(例如95%)。总重要性所占比例也要维持在一定的百分比。

基于特征重要性的方法最适合用来对树型结构模型进行预测。基于重要性的方法是随机的,也是一种黑盒方法,因为模型判定特征是否相关并不透明的。所以在使用基于特征重要性的方法时,应多次运行以查看结果如何变化,并尽可能创建多个具有不同参数的数据集以进行测试!

唯一值特征
最唯一值特征选择法是相当基本的:查找有唯一值的列。只有一个唯一值的特征对于机器学习来说是无用的,因为这个特征的方差为零。例如,只有一个值的特征不能作为树型结构模型的节点(因为该特征不能再分组了)。

绘制各个区间唯一值数量的直方图:

需要记住的一点是:默认在计算Pandas 中唯一值之前,NaNs会被删除。

删除特征

确定了要删除特征后,有两个选择可以删除它们。所有要删除的特征都存储在FeatureSelector的ops属性中,可以根据出现的列表手动删除特征。另一种选择是使用remove内置函数。

使用remove函数删除特征时需传入methods。如果想要使用所有的实现方法,只需传入methods = 'all'。
# Remove the features from all methods (returns a df)
train_removed = fs.remove(methods = 'all')
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run
Removed 140 features.

该方法删除特征后返回一个dataframe,在机器学习过程中创建的one-hot编码特征也被删除:
train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
Removed 187 features including one-hot features.

在开始操作之前先检查要删除的特征!原始数据集存储在FeatureSelector的data属性中作为备份!

结论

在训练机器学习模型之前,特征选择器类实现了一些常见的删除特征的操作。它具有选择要删除特征和绘图的功能。类内方法可以单独运行,也可以为实现高效的工作流而同时运行。

Missing方法, collinear方法和single_unique方法都是具有确定性的,而基于特征重要性的方法会随着每次运行而改变。像机器学习一样,特征选择很大程度上是经验主义。测试多组数据才能得到最佳结果,所以最好多尝试几次。特征选择器提供了一种快速评估特征选择参数的方法。

本文由阿里云云栖社区组织翻译。

文章原标题《a-feature-selection-tool-for-machine-learning-in-python》

作者: William Koehrsen译者:吴兆青,审校:袁虎。

文章为简译,更为详细的内容,请查看原文文章

推荐阅读