特征选择之FeatureSelector工具
项目地址:https://github.com/WillKoehrsen/feature-selector
特征选择(feature selection)是查找和选择数据集中最有用特征的过程,是机器学习流程中的一大关键步骤。不必要的特征会降低训练速度、降低模型可解释性,并且最重要的是还会降低其在测试集上的泛化表现。
目前存在一些专用型的特征选择方法,我常常要一遍又一遍地将它们应用于机器学习问题,这实在让人心累。所以我用 Python 构建了一个特征选择类并开放在了 GitHub 上。这个 FeatureSelector 包含一些最常用的特征选择方法:
具有高缺失值百分比的特征
共线性(高度相关的)特征
在基于树的模型中重要度为零的特征
重要度较低的特征
具有单个唯一值(unique value)的特征
在本文中,我们将介绍在示例机器学习数据集上使用 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 种用于查找待移除特征的方法。我们可以访问任何已被识别出来的特征并通过人工方式将它们移出数据,也可以使用 FeatureSelector 中的 remove 函数。
这里我们将介绍其中每种识别方法,还将展示如何同时运行这 5 种方法。此外,FeatureSelector 还有几个图表绘制功能,因为可视化地检查数据是机器学习的一大关键部分。
缺失值
查找和移除特征的第一个方法很简单:查找缺失值比例超过特定阈值的特征。下面的调用能识别缺失值比例超过 60% 的特征(粗体是输出结果)。
fs.identify_missing(missing_threshold = 0.6)
17 features with greater than 0.60 missing values.
要查看待移除特征,我们可以读取 FeatureSelector 的 ops 属性,这是一个 Python 特征词典,特征会以列表的形式给出。
missing_features = fs.ops[‘missing‘]
missing_features[:5]
[‘OWN_CAR_AGE‘,
‘YEARS_BUILD_AVG‘,
‘COMMONAREA_AVG‘,
‘FLOORSMIN_AVG‘,
‘LIVINGAPARTMENTS_AVG‘]
最后,我们可以绘制一张所有特制的缺失值分布图:
共线性特征
共线性特征是指彼此之间高度关联的特征。在机器学习领域,高方差和较低的模型可解释性导致在测试集上的泛化能力下降。
identify_collinear 方法能基于指定的相关系数值查找共线性特征。对于每一对相关的特征,它都会标识出其中要移除的一个(因为我们只需要移除其中一个):
fs.identify_collinear(correlation_threshold = 0.98)
21 features with a correlation magnitude greater than 0.98.
使用热图可以很好地可视化共线性。下图展示了所有至少有一个相关关系(correlation)超过阈值的特征:
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_importance 函数能根据梯度提升机(GBM)学习模型查找重要度为零的特征。
我们可以使用基于树的机器学习模型(比如 boosting ensemble)求取特征重要度。这个重要度的绝对值没有相对值重要,我们可以将相对值用于确定对一个任务而言最相关的特征。我们还可以通过移除零重要度特征来在特征选择中使用特征重要度。在基于树的模型中,零重要度的特征不会被用于分割任何节点,所以我们可以移除它们而不影响模型表现。
FeatureSelector 能使用来自 LightGBM 库的梯度提升机来得到特征重要度。为了降低方差,所得到的特征重要度是在 GBM 的 10 轮训练上的平均。另外,该模型还使用早停(early stopping)进行训练(也可关闭该选项),以防止在训练数据上过拟合。
下面的代码调用了该方法并提取出了零重要度特征:
# 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_iterations:训练轮数,最后结果取多轮的平均
early_stopping:是否为训练模型使用早停
这时候我们可以使用 plot_feature_importances 绘制两个图表:
# plot the feature importances
fs.plot_feature_importances(threshold = 0.99, plot_n = 12)
124 features required for 0.99 of cumulative importance