使用FeatureSelector实现高效的机器学习工作流程
特征选择是查找和选择数据集中最有用特征的过程,是机器学习管道的关键步骤。不必要的功能降低了训练速度,降低了模型的可解释性,并且最重要的是降低了测试集的泛化性能。
在FeatureSelector(https://github.com/WillKoehrsen/feature-selector)包括了一些最常见的特征选择方法:
- 具有高百分比缺失值的特征
- 共线(高度相关)特征
- 在基于树的模型中具有零重要性的特征
- 低重要性的特征
- 具有单个惟一值的特征
在本文中,我们将通过使用FeatureSelector示例机器学习数据集进行介绍。我们将看到它如何让我们快速实施这些方法,从而实现更高效的工作流程。
示例数据集
在这个例子中,我们将使用Kaggle 的Home Credit Default Risk机器学习竞赛中的一个数据样本。整个数据集可供下载(https://www.kaggle.com/c/home-credit-default-risk/data),在这里我们将使用一个样本进行说明。
示例数据。TARGET是分类标签
这是一个监督分类问题,这是一个很好的数据集,因为它有许多缺失的值,许多高度相关的(共线)特性,以及许多不相关的特性,这些特性对机器学习模型没有帮助。
创建一个实例
要创建FeatureSelector类的实例,我们需要传入结构化数据集,其中包含行中的观察值和列中的特征。我们可以仅使用一些功能的方法,但基于重要性的方法也需要训练标签。由于我们有监督分类任务,因此我们将使用一组特征和一组标签。
(请确保在与此目录相同的目录下运行feature_selector.py)
from feature_selector import FeatureSelector
# Features are in train and labels are in train_labels
fs = FeatureSelector(data = train, labels = train_labels)
方法
特征选择器有五种方法来查找要移除的特征。我们可以访问任何已识别的特征并手动从数据中删除它们,或使用特征选择器中的remove函数。
在这里,我们将通过每种识别方法,并展示如何全部运行。在FeatureSelector另外有几个绘图功能,因为可视化检测数据是机器学习的重要组成部分。
缺少值
查找删除要素的第一种方法很简单:找到缺少高于指定阈值的部分缺失值的要素。以下调用识别缺失值超过60%的特征
fs.identify_missing(missing_threshold = 0.6)
17 features with greater than 0.60 missing values.
我们可以在数据框的每一列中看到缺失值的一小部分:
fs.missing_stats.head()
为了查看要删除的特性,我们访问了FeatureSelector的ops属性,该FeatureSelector是特征值为列表。
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()
像以前一样,我们可以访问将被删除的整个关联特征列表,或者查看数据框中高度相关的特征对
# list of collinear features to remove
collinear_features = fs.ops['collinear']
# dataframe of collinear features
fs.record_collinear.head()
如果我们想调查我们的数据集,我们也可以通过传递plot_all = True给调用来绘制数据中所有相关性的图表:
零重要特征
前两种方法可以应用于任何结构化数据集并且是确定性的 - 每次给定阈值时结果都是相同的。下一个方法仅针对监督机器学习问题而设计,其中我们有训练模型的标签并且是非确定性的。该identify_zero_importance 函数根据梯度提升机器(GBM)学习模型查找具有零重要性的特征。
通过基于树的机器学习模型,例如boosting ensemble,我们可以发现特性的重要性。重要性的绝对值并不像相对值那么重要,我们可以用相对值来确定任务最相关的特征。我们还可以通过移除零重要性的特征来使用特征选择。在基于树的模型中,不使用不重要的特征来分割任何节点,因此我们可以在不影响模型性能的情况下删除它们。
特征选择器使用来自LightGBM库的gradient boosting machine来发现特征输入。为了减少差异,对特征输入进行平均超过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 :对应于我们的问题的“分类”或“回归”
- eval_metric:用于提早停止的度量标准(如果禁用提前停止,则不需要)
- n_iterations :训练运行次数,以平均特征重要性
- early_stopping:是否使用提前停止训练模型
绘制图表:
# plot the feature importances
fs.plot_feature_importances(threshold = 0.99, plot_n = 12)
124 features required for 0.99 of cumulative importance
在左边,我们有plot_n最重要的特征(按照标准化重要性绘制,总和为1)。在右侧,我们对特征数量具有累积重要性。垂直线绘制在threshold累积的重要性,在这种情况下是99%。
对于基于重要性的方法,需要记住两点:
- 训练gradient boosting machine是随机的,意味着每次模型运行时,要素重要性都会发生变化
这应该不会产生重大影响(至少最重要的功能不会突然变),但它会改变某些特征的排序。它也会影响识别的零重要性特征的数量。如果特征重要性每次都改变,不要感到惊讶!
- 为了训练机器学习模型,这些特征首先是one-hot 编码。这意味着被认为具有0重要性的一些特征可能是在建模期间添加的one-hot 编码特征。
当我们进入特征删除阶段时,可以选择删除所有添加的one-hot 编码特征。但是,如果我们在特征选择之后进行机器学习,那么我们必须对特征进行one-hot 编码!
低重要性特征
下一个方法基于零重要性函数,使用模型中的要素重要性进一步选择。该函数identify_low_importance找到不影响指定的总重要性的最低重要性特征。
例如,下面的调用找到了达到总重要性99%所不需要的最不重要的特征:
fs.identify_low_importance(cumulative_importance = 0.99)
123 features required for cumulative importance of 0.99 after one hot encoding.
116 features do not contribute to cumulative importance of 0.99.
这种方法的结果将在每次训练中发生变化。
要查看数据框中的所有要素重要性,请执行以下操作:
fs.feature_importances.head(10)
low_important方法借用了一种使用主成分分析(PCA)的方法。基于特征重要性的方法只有在我们要使用基于树的模型进行预测时才适用。除了随机性之外,基于重要性的方法是一种黑盒方法,因为我们并不真正知道为什么模型认为这些特征是无关紧要的。如果使用这些方法,请多次运行它们以查看结果如何变化,并可能创建具有不同参数的多个数据集进行测试!
单一的唯一价值特征
最后的方法非常基础:找到任何具有单一唯一值的列。仅具有一个唯一值的特征对于机器学习不具有用处,因为此特征具有零差异。例如,基于树的模型不能仅使用一个值对特征进行分割(因为没有组将观察分割)。
这里没有参数可供选择,与其他方法不同:
fs.identify_single_unique()
4 features with a single unique value.
我们可以绘制每个类别中唯一值数量的直方图:
fs.plot_unique()
需要记住的一点是,在默认情况下,NaN在计算Pandas中的唯一值之前将其丢弃。
移除特征
一旦我们确定了要丢弃的特征,我们就有两个选项可以删除它们。所有要删除的特征都存储在FeatureSelector的ops字典中,我们可以使用列表手动删除特征。另一种选择是使用remove内置函数。
我们传入methods以用于删除特征。如果我们想使用所有实现的方法,我们只需传入methods = 'all'
#从所有方法中删除特征(返回一个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编码features:
train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
Removed 187 features including one-hot features.
在继续操作之前检查将要删除的特征可能是一个好主意!原始数据集存储在作为备份的data属性中FeatureSelector!
一次运行所有方法
与其单独使用这些方法,我们可以全部使用它们identify_all。这需要每个方法的参数字典:
fs.identify_all(selection_params = {'missing_threshold':0.6,
'correlation_threshold':0.98,
'task':'classification',
'eval_metric':'auc',
'cumulative_importance':0.99})
151 total features out of 255 identified for removal after one-hot encoding.
注意,由于我们重新运行模型,所有特性的数量将会改变。然后可以调用remove函数来丢弃这些特征。
结论
特征选择器类在训练机器学习模型之前执行几个常用的操作以去除特征。它提供了识别删除特征以及可视化的特征。方法可以单独运行或同时运行,以实现高效的工作流程。
missing,collinear和single_unique方法是确定性的,而基于特征的重要性的方法将每次运行时改变。特征选择很像机器学习领域,很大程度上是经验性的,需要测试多个组合才能找到最佳答案