本文介绍一个特征选择神器:特征选择器是用于减少机器学习数据集的维数的工具,可以傻瓜式地进行特征选择,两行代码即可搞定!!
来源:Will Koehrsen
代码整理及注释翻译:黄海广
代码和数据下载地址:
https://github.com/fengdu78/Data-Science-Notes/tree/master/9.feature-engineering/FeatureSelectorUsage
实现的功能
该选择器基于Python编写,有五种方法来标识要删除的特征:
缺失值
唯一值
共线特征
零重要性特征
低重要性特征
使用方法
特征选择器(Feature Selector)的用法
在这个Jupyter文件中, 我们将使用 FeatureSelector
类来选择数据集中要删除的特征,这个类提供五种方法来查找要删除的功能:
查找缺失分数大于指定阈值的列
查找只有唯一值的特征
查找由相关系数大于指定值的共线特征
使用梯度提升算法查找具有零重要性的特征
使用梯度提升算法查找中查找对指定的累积特征重要性无贡献的特征
FeatureSelector
仍在进一步开发中! 欢迎大家在github提交PR.
from feature_selector import FeatureSelector
import pandas as pd
示例数据集
该数据集被用作Kaggle上房屋信用违约风险竞赛的(https://www.kaggle.com/c/home-credit-default-risk) 一部分(文末提供下载)。它旨在用于有监督的机器学习分类任务,其目的是预测客户是否会拖欠贷款。您可以在此处下载整个数据集,我们将处理10,000行的一小部分样本。
特征选择器旨在用于机器学习任务,但可以应用于任何数据集。基于特征重要性的方法需要使用机器学习的监督学习问题。
train = pd.read_csv('data/credit_example.csv')
train_labels = train['TARGET']
train.head()
5 rows × 122 columns
数据集中有几个分类列。`FeatureSelector`处理这些特征重要性的时候使用独热编码。train = train.drop(columns = ['TARGET'])
实施
在FeatureSelector
具有用于标识列,以除去五种特征 :
identify_missing
(查找缺失值)identify_single_unique
(查找唯一值)identify_collinear
(查找共线特征)identify_zero_importance
(查找零重要特征)identify_low_importance
(查找低重要特征)
这些方法找到要根据指定条件删除的特征。标识的特征存储在 FeatureSelector
的 ops
属性(Python词典)中。我们可以手动删除已识别的特征,也可以使用 FeatureSelector
中的删除特征函数真正删除特征。
创建实例
FeatureSelector
仅需要一个在行中具有观察值而在列中具有特征的数据集(标准结构化数据)。我们正在处理机器学习的分类问题,因此我们也需要训练的标签。
fs = FeatureSelector(data = train, labels = train_labels)
1. 缺失值
第一种特征选择方法很简单:找到丢失分数大于指定阈值的任何列。在此示例中,我们将使用阈值0.6,这对应于查找缺失值超过60%的特征。(此方法不会首先对特征进行一次独热编码)。
fs.identify_missing(missing_threshold=0.6)
17 features with greater than 0.60 missing values.
可以通过 FeatureSelector
对象的ops
词典访问已确定要删除的特征。
missing_features = fs.ops['missing']
missing_features[:10]
['OWN_CAR_AGE',
'YEARS_BUILD_AVG',
'COMMONAREA_AVG',
'FLOORSMIN_AVG',
'LIVINGAPARTMENTS_AVG',
'NONLIVINGAPARTMENTS_AVG',
'YEARS_BUILD_MODE',
'COMMONAREA_MODE',
'FLOORSMIN_MODE',
'LIVINGAPARTMENTS_MODE']
我们还可以绘制数据集中所有列的缺失列分数的直方图。
fs.plot_missing()
![](https://i-blog.csdnimg.cn/blog_migrate/2464a0639942a6627b0a27087125c9ac.png)
有关缺失分数的详细信息,我们可以访问missing_stats
属性,这是所有特征缺失分数的DataFrame。
fs.missing_stats.head(10)
missing_fraction | |
---|---|
COMMONAREA_AVG | 0.6953 |
COMMONAREA_MODE | 0.6953 |
COMMONAREA_MEDI | 0.6953 |
NONLIVINGAPARTMENTS_AVG | 0.6945 |
NONLIVINGAPARTMENTS_MODE | 0.6945 |
NONLIVINGAPARTMENTS_MEDI | 0.6945 |
LIVINGAPARTMENTS_MEDI | 0.6846 |
LIVINGAPARTMENTS_AVG | 0.6846 |
LIVINGAPARTMENTS_MODE | 0.6846 |
FONDKAPREMONT_MODE | 0.6820 |
2. 唯一值
下一个方法很简单:找到只有一个唯一值的所有特征。(这不会对特征进行独热编码)。
fs.identify_single_unique()
4 features with a single unique value.
single_unique = fs.ops['single_unique']
single_unique
['FLAG_MOBIL', 'FLAG_DOCUMENT_10', 'FLAG_DOCUMENT_12', 'FLAG_DOCUMENT_17']
我们可以绘制数据集中每个特征中唯一值数量的直方图。
fs.plot_unique()
![](https://i-blog.csdnimg.cn/blog_migrate/3950b394be5585fe308fe5fa2104665a.png)
最后,我们可以访问一个DataFrame,其中包含每个特征的唯一值数量。
fs.unique_stats.sample(5)
nunique | |
---|---|
DAYS_EMPLOYED | 4210 |
REGION_RATING_CLIENT | 3 |
FLAG_DOCUMENT_20 | 2 |
FLAG_DOCUMENT_15 | 2 |
NONLIVINGAREA_MEDI | 993 |
3. 共线(高相关性) 特征
该方法基于皮尔森相关系数找到共线特征对。对于高于指定阈值(就绝对值而言)的每一对,它标识要删除的变量之一。我们需要传递一个 correlation_threshold
。
此方法基于在:https://chrisalbon.com/machine_learning/feature_selection/drop_highly_correlated_features/ 中找到的代码。
对于每一对,将要删除的特征是在DataFrame中列排序方面排在最后的特征。(除非one_hot = True
,否则此方法不会预先对数据进行一次独热编码。因此,仅在数字列之间计算相关性)
fs.identify_collinear(correlation_threshold=0.975)
24 features with a correlation magnitude greater than 0.97.
correlated_features = fs.ops['collinear']
correlated_features[:5]
['AMT_GOODS_PRICE',
'FLAG_EMP_PHONE',
'YEARS_BUILD_MODE',
'COMMONAREA_MODE',
'ELEVATORS_MODE']
我们可以查看阈值以上相关性的热图。将要删除的特征位于x轴上。
fs.plot_collinear()
![](https://i-blog.csdnimg.cn/blog_migrate/6292ef2c2275ca37460bd1b8e2c0fa05.png)
要绘制数据中的所有相关性,我们可以将 plot_all = True
传递给 plot_collinear
函数。
fs.plot_collinear(plot_all=True)
![](https://i-blog.csdnimg.cn/blog_migrate/cef53f81665dfaf96eb2acd71ffdacb5.png)
fs.identify_collinear(correlation_threshold=0.98)
fs.plot_collinear()
21 features with a correlation magnitude greater than 0.98.
![](https://i-blog.csdnimg.cn/blog_migrate/854193ba04e332f0cc477e9b5700b10f.png)
要查看阈值以上的相关细节,我们访问record_collinear
属性,它是一个DataFrame。 drop_feature
将被删除,并且对于每个将被删除的特征,它与 corr_feature
可能存在多个相关性,而这些相关性都高于correlation_threshold
。
fs.record_collinear.head()
corr_feature | corr_value | drop_feature | |
---|---|---|---|
0 | AMT_CREDIT | 0.987232 | AMT_GOODS_PRICE |
1 | DAYS_EMPLOYED | -0.999533 | FLAG_EMP_PHONE |
2 | YEARS_BUILD_AVG | 0.992120 | YEARS_BUILD_MODE |
3 | COMMONAREA_AVG | 0.988074 | COMMONAREA_MODE |
4 | FLOORSMAX_AVG | 0.984663 | FLOORSMAX_MODE |
4. 零重要特征
此方法依赖于机器学习模型来识别要删除的特征。因此,它是有标签的监督学习问题。该方法通过使用LightGBM库中实现的梯度增强机找到特征重要性。
为了减少所计算的特征重要性的差异,默认情况下对模型进行了10次训练。默认情况下,还使用验证集(训练数据的15%)通过提前停止训练模型,以识别要训练的最优估计量。可以将以下参数传递给identify_zero_importance
方法:
task
: 可以是classification
或regression
。指标和标签必须与任务匹配。eval_metric
: 用于提前停止的度量(例如,用于分类的auc或用于回归的l2
)。要查看可用指标的列表,请参阅LightGBM文档:(http://testlightgbm.readthedocs.io/en/latest/Parameters.html#metric-parameters)。n_iterations
: 训练次数。特征重要性是在训练运行中平均得出的 (默认为10)。early_stopping
: 训练模型时是否使用提前停止(默认= True)。当验证集的性能对于指定数量的估计量(此实现中默认为100)不再降低时,提早停止将停止训练估计量(决策树)。早停是一种正则化形式,用于防止训练数据过拟合。
首先对数据进行一次独热编码,以供模型使用。这意味着某些零重要性特征可以通过一键编码来创建。要查看单编码的列,我们可以访问 FeatureSelector
的one_hot_features
。
注意:与其他方法相比,模型的特征重要性是不确定的(具有少许随机性)。每次运行此方法时,其结果都可能更改。
fs.identify_zero_importance(task = 'classification', eval_metric = 'auc',
n_iterations = 10, early_stopping = True)
Training Gradient Boosting Model
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[57] valid_0's auc: 0.760957 valid_0's binary_logloss: 0.250579
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[29] valid_0's auc: 0.681283 valid_0's binary_logloss: 0.266277
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[50] valid_0's auc: 0.73881 valid_0's binary_logloss: 0.257822
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[34] valid_0's auc: 0.720575 valid_0's binary_logloss: 0.262094
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[48] valid_0's auc: 0.769376 valid_0's binary_logloss: 0.247709
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[35] valid_0's auc: 0.713877 valid_0's binary_logloss: 0.262254
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[76] valid_0's auc: 0.753081 valid_0's binary_logloss: 0.251867
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[70] valid_0's auc: 0.722385 valid_0's binary_logloss: 0.259535
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[45] valid_0's auc: 0.752703 valid_0's binary_logloss: 0.252175
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[49] valid_0's auc: 0.757385 valid_0's binary_logloss: 0.250356
81 features with zero importance after one-hot encoding.
运行梯度提升模型需要对特征进行独热编码。这些特征保存在 FeatureSelector
的 one_hot_features
属性中。原始特征保存在base_features
中。
one_hot_features = fs.one_hot_features
base_features = fs.base_features
print('There are %d original features' % len(base_features))
print('There are %d one-hot features' % len(one_hot_features))
There are 121 original features
There are 134 one-hot features
FeatureSelector
的 data
属性保存原始DataFrame。独热编码后, data_all
属性将保留原始数据以及独热编码特征。
fs.data_all.head(10)
10 rows × 255 columns
我们可以使用多种方法来检查特征重要性的结果。首先,我们可以访问具有零重要性的特征列表。zero_importance_features = fs.ops['zero_importance']
zero_importance_features[10:15]
['ORGANIZATION_TYPE_Transport: type 1',
'ORGANIZATION_TYPE_Security',
'FLAG_DOCUMENT_15',
'FLAG_DOCUMENT_17',
'ORGANIZATION_TYPE_Religion']
画出特征重要性
使用 plot_feature_importances
的特征重要性画图将向我们显示 plot_n
最重要的特征(按归一化比例将特征加总为1)。它还向我们显示了累积特征重要性与特征数量之间的关系。
当我们绘制特征重要性时,我们可以传递一个阈值,该阈值标识达到指定的累积特征重要性所需的特征数量。例如,threshold = 0.99
将告诉我们占总重要性的99%所需的特征数量。
fs.plot_feature_importances(threshold = 0.99, plot_n = 12)
![](https://i-blog.csdnimg.cn/blog_migrate/b5e2ab1ce1c20b6834e0c6dfb6ce0d63.png)
![](https://i-blog.csdnimg.cn/blog_migrate/352f5a65cd75dbc8b047a8082186a3fd.png)
111 features required for 0.99 of cumulative importance
在 FeatureSelector
中的 feature_importances
属性中可以访问所有的特征重要性。
fs.feature_importances.head(10)
feature | importance | normalized_importance | cumulative_importance | |
---|---|---|---|---|
0 | EXT_SOURCE_2 | 145.2 | 0.098174 | 0.098174 |
1 | EXT_SOURCE_3 | 127.7 | 0.086342 | 0.184517 |
2 | EXT_SOURCE_1 | 82.7 | 0.055916 | 0.240433 |
3 | DAYS_BIRTH | 71.4 | 0.048276 | 0.288709 |
4 | DAYS_REGISTRATION | 64.1 | 0.043340 | 0.332049 |
5 | DAYS_ID_PUBLISH | 59.3 | 0.040095 | 0.372143 |
6 | SK_ID_CURR | 57.7 | 0.039013 | 0.411156 |
7 | DAYS_EMPLOYED | 55.5 | 0.037525 | 0.448682 |
8 | DAYS_LAST_PHONE_CHANGE | 47.0 | 0.031778 | 0.480460 |
9 | AMT_INCOME_TOTAL | 41.0 | 0.027721 | 0.508181 |
one_hundred_features = list(fs.feature_importances.loc[:99, 'feature'])
len(one_hundred_features)
100
5. 低重要性特征
此方法使用梯度提升算法(必须首先运行identify_zero_importance
)通过查找达到指定的累积总特征重要性所需的最低特征重要性的特征,来构建特征重要性。例如,如果我们输入0.99,则将找到最不重要的特征重要性,这些特征总的不到总特征重要性的99%。
使用此方法时,我们必须已经运行了identify_zero_importance
,并且需要传递一个cumulative_importance
,该值占总特征重要性的一部分。
**注意:**此方法建立在梯度提升模型的重要性基础之上,并且还是不确定的。我建议使用不同的参数多次运行这两种方法,并测试每个结果的特征集,而不是只选择一个数字。
fs.identify_low_importance(cumulative_importance = 0.99)
110 features required for cumulative importance of 0.99 after one hot encoding.
129 features do not contribute to cumulative importance of 0.99.
要删除的低重要性特征是指那些对指定的累积重要性无贡献的特征。这些特征也可以在 ops
词典中找到。
low_importance_features = fs.ops['low_importance']
low_importance_features[:5]
['NAME_FAMILY_STATUS_Widow',
'WEEKDAY_APPR_PROCESS_START_SATURDAY',
'ORGANIZATION_TYPE_Business Entity Type 2',
'ORGANIZATION_TYPE_Business Entity Type 1',
'NAME_INCOME_TYPE_State servant']
删除特征
一旦确定了要删除的特征,便可以通过多种方式删除这些特征。我们可以访问removal_ops
词典中的任何功能列表,并手动删除列。我们还可以使用 remove
方法,传入标识我们要删除的特征的方法。
此方法返回结果数据,然后我们可以将其用于机器学习。仍然可以在特征选择器的 data
属性中访问原始数据。
请注意用于删除特征的方法!在使用删除特征之前,最好先检查将要remove
的特征。
train_no_missing = fs.remove(methods = ['missing'])
Removed 17 features.
train_no_missing_zero = fs.remove(methods = ['missing', 'zero_importance'])
Removed 98 features.
要从所有方法中删除特征,请传入 method='all'
。在执行此操作之前,我们可以使用check_removal
检查将删除了多少个特征。这将返回已被识别为要删除的所有特征的列表。
all_to_remove = fs.check_removal()
all_to_remove[10:25]
Total of 156 features identified for removal
['FLAG_OWN_REALTY_Y',
'FLAG_DOCUMENT_19',
'ORGANIZATION_TYPE_Agriculture',
'FLOORSMIN_MEDI',
'ORGANIZATION_TYPE_Restaurant',
'NAME_HOUSING_TYPE_With parents',
'NONLIVINGAREA_MEDI',
'NAME_INCOME_TYPE_Pensioner',
'HOUSETYPE_MODE_specific housing',
'ORGANIZATION_TYPE_Industry: type 5',
'ORGANIZATION_TYPE_Realtor',
'OCCUPATION_TYPE_Cleaning staff',
'ORGANIZATION_TYPE_Industry: type 12',
'OCCUPATION_TYPE_Realty agents',
'ORGANIZATION_TYPE_Trade: type 6']
现在我们可以删除所有已识别的特征。
train_removed = fs.remove(methods = 'all')
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run
Removed 156 features.
处理独热特征
如果我们查看返回的DataFrame,可能会注意到原始数据中没有的几个新列。这些是在对数据进行独热编码以进行机器学习时创建的。要删除所有独热特征,我们可以将 keep_one_hot = False
传递给 remove
方法。
train_removed_all = fs.remove(methods = 'all', keep_one_hot=False)
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run
Removed 190 features including one-hot features.
print('Original Number of Features', train.shape[1])
print('Final Number of Features: ', train_removed_all.shape[1])
Original Number of Features 121
Final Number of Features: 65
使用所有方法的替代选项
如果我们不想一次运行一个识别方法,则可以使用identify_all
在一次调用中运行所有方法。对于此功能,我们需要传入参数字典以用于每种单独的识别方法。
以下代码在一个调用中完成了上述步骤。
fs = FeatureSelector(data = train, labels = train_labels)
fs.identify_all(selection_params = {'missing_threshold': 0.6, 'correlation_threshold': 0.98,
'task': 'classification', 'eval_metric': 'auc',
'cumulative_importance': 0.99})
17 features with greater than 0.60 missing values.
4 features with a single unique value.
21 features with a correlation magnitude greater than 0.98.
Training Gradient Boosting Model
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[46] valid_0's auc: 0.743917 valid_0's binary_logloss: 0.254668
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[82] valid_0's auc: 0.766619 valid_0's binary_logloss: 0.244264
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[55] valid_0's auc: 0.72614 valid_0's binary_logloss: 0.26157
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[81] valid_0's auc: 0.756286 valid_0's binary_logloss: 0.251242
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[39] valid_0's auc: 0.686351 valid_0's binary_logloss: 0.269367
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[41] valid_0's auc: 0.744124 valid_0's binary_logloss: 0.255549
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[90] valid_0's auc: 0.761742 valid_0's binary_logloss: 0.249119
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[49] valid_0's auc: 0.751569 valid_0's binary_logloss: 0.254504
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[76] valid_0's auc: 0.726789 valid_0's binary_logloss: 0.257181
Training until validation scores don't improve for 100 rounds.
Early stopping, best iteration is:
[46] valid_0's auc: 0.714889 valid_0's binary_logloss: 0.260482
80 features with zero importance after one-hot encoding.
115 features required for cumulative importance of 0.99 after one hot encoding.
124 features do not contribute to cumulative importance of 0.99.
150 total features out of 255 identified for removal after one-hot encoding.
train_removed_all_once = fs.remove(methods = 'all', keep_one_hot = True)
['missing', 'single_unique', 'collinear', 'zero_importance', 'low_importance'] methods have been run
Removed 150 features.
fs.feature_importances.head()
feature | importance | normalized_importance | cumulative_importance | |
---|---|---|---|---|
0 | EXT_SOURCE_2 | 165.3 | 0.091074 | 0.091074 |
1 | EXT_SOURCE_3 | 154.7 | 0.085234 | 0.176309 |
2 | EXT_SOURCE_1 | 97.5 | 0.053719 | 0.230028 |
3 | DAYS_BIRTH | 84.6 | 0.046612 | 0.276639 |
4 | DAYS_REGISTRATION | 75.9 | 0.041818 | 0.318457 |
由于特征重要性已更改,因此删除的特征数略有差异。由缺失的(missing
)、单一的(single_unique
)和共线( collinear
)确定要删除的特征数量将保持不变,因为它们是确定性的,但是由于多次训练模型,零重要性( zero_importance
)和低重要性(low_importance
)的特征数量可能会有所不同。
结论
本笔记本演示了如何使用FeatureSelector
类从数据集中删除特征。此实现中有几个重要注意事项:
在机器学习模型的多次运行中,特征重要性将发生变化。
决定是否保留从一个独热编码创建的额外特征。
为不同的参数尝试几个不同的值,以确定哪些参数最适合机器学习任务。
对于相同的参数,缺失的(
missing
)、单一的(single_unique
)和共线(collinear
)的输出将保持不变。特征选择是机器学习工作流中的一个关键步骤,它可能需要多次迭代来优化。
我很感激你对这个项目的任何评论、反馈或帮助。
代码和数据下载地址:
https://github.com/fengdu78/Data-Science-Notes/tree/master/9.feature-engineering/FeatureSelectorUsage
参考
WillKoehrsen:https://github.com/WillKoehrsen/feature-selector
备注:公众号菜单包含了整理了一本AI小抄,非常适合在通勤路上用学习。
往期精彩回顾
适合初学者入门人工智能的路线及资料下载机器学习在线手册深度学习在线手册AI基础下载(第一部分)备注:加入本站微信群或者qq群,请回复“加群”获取一折本站知识星球优惠券,请回复“知识星球”
喜欢文章,点个在看