基于Python的特征自动化选择:两行代码完成特征工程

·  阅读 1121

本文介绍一个特征选择神器:特征选择器是用于减少机器学习数据集的维数的工具,可以傻瓜式地进行特征选择,两行代码即可搞定!!

来源:Will Koehrsen

代码整理及注释翻译:黄海广

代码和数据下载地址:

github.com/fengdu78/Da…

实现的功能

该选择器基于Python编写,有五种方法来标识要删除的特征:

  • 缺失值
  • 唯一值
  • 共线特征
  • 零重要性特征
  • 低重要性特征

使用方法

 特征选择器(Feature Selector)的用法

在这个Jupyter文件中, 我们将使用 FeatureSelector 类来选择数据集中要删除的特征,这个类提供五种方法来查找要删除的功能:

  1. 查找缺失分数大于指定阈值的列
  2. 查找只有唯一值的特征
  3. 查找由相关系数大于指定值的共线特征
  4. 使用梯度提升算法查找具有零重要性的特征
  5. 使用梯度提升算法查找中查找对指定的累积特征重要性无贡献的特征

FeatureSelector 仍在进一步开发中! 欢迎大家在github提交PR.

from feature_selector import FeatureSelector

import pandas as pd
复制代码

示例数据集

该数据集被用作Kaggle上房屋信用违约风险竞赛的(www.kaggle.com/c/home-cred…)  一部分(文末提供下载)。它旨在用于有监督的机器学习分类任务,其目的是预测客户是否会拖欠贷款。您可以在此处下载整个数据集,我们将处理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(查找低重要特征)

这些方法找到要根据指定条件删除的特征。标识的特征存储在 FeatureSelectorops 属性(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()
复制代码

有关缺失分数的详细信息,我们可以访问missing_stats属性,这是所有特征缺失分数的DataFrame。

fs.missing_stats.head(10)
复制代码
missing_fraction
COMMONAREA_AVG0.6953
COMMONAREA_MODE0.6953
COMMONAREA_MEDI0.6953
NONLIVINGAPARTMENTS_AVG0.6945
NONLIVINGAPARTMENTS_MODE0.6945
NONLIVINGAPARTMENTS_MEDI0.6945
LIVINGAPARTMENTS_MEDI0.6846
LIVINGAPARTMENTS_AVG0.6846
LIVINGAPARTMENTS_MODE0.6846
FONDKAPREMONT_MODE0.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()
复制代码

最后,我们可以访问一个DataFrame,其中包含每个特征的唯一值数量。

fs.unique_stats.sample(5)
复制代码
nunique
DAYS_EMPLOYED4210
REGION_RATING_CLIENT3
FLAG_DOCUMENT_202
FLAG_DOCUMENT_152
NONLIVINGAREA_MEDI993

3. 共线(高相关性) 特征

该方法基于皮尔森相关系数找到共线特征对。对于高于指定阈值(就绝对值而言)的每一对,它标识要删除的变量之一。我们需要传递一个 correlation_threshold

此方法基于在:chrisalbon.com/machine_lea… 中找到的代码。

对于每一对,将要删除的特征是在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()
复制代码

要绘制数据中的所有相关性,我们可以将 plot_all = True 传递给 plot_collinear函数。

fs.plot_collinear(plot_all=True)
复制代码

fs.identify_collinear(correlation_threshold=0.98)
fs.plot_collinear()
复制代码
21 features with a correlation magnitude greater than 0.98.
复制代码

要查看阈值以上的相关细节,我们访问record_collinear 属性,它是一个DataFrame。 drop_feature 将被删除,并且对于每个将被删除的特征,它与 corr_feature可能存在多个相关性,而这些相关性都高于correlation_threshold

fs.record_collinear.head()
复制代码
corr_featurecorr_valuedrop_feature
0AMT_CREDIT0.987232AMT_GOODS_PRICE
1DAYS_EMPLOYED-0.999533FLAG_EMP_PHONE
2YEARS_BUILD_AVG0.992120YEARS_BUILD_MODE
3COMMONAREA_AVG0.988074COMMONAREA_MODE
4FLOORSMAX_AVG0.984663FLOORSMAX_MODE

 

4. 零重要特征

此方法依赖于机器学习模型来识别要删除的特征。因此,它是有标签的监督学习问题。该方法通过使用LightGBM库中实现的梯度增强机找到特征重要性。

为了减少所计算的特征重要性的差异,默认情况下对模型进行了10次训练。默认情况下,还使用验证集(训练数据的15%)通过提前停止训练模型,以识别要训练的最优估计量。可以将以下参数传递给identify_zero_importance 方法:

  • task: 可以是 classificationregression。指标和标签必须与任务匹配。
  • eval_metric: 用于提前停止的度量(例如,用于分类的auc或用于回归的l2 )。要查看可用指标的列表,请参阅LightGBM文档:(testlightgbm.readthedocs.io/en/latest/P…
  • n_iterations: 训练次数。特征重要性是在训练运行中平均得出的 (默认为10)。
  • early_stopping: 训练模型时是否使用提前停止(默认= True)。当验证集的性能对于指定数量的估计量(此实现中默认为100)不再降低时,提早停止将停止训练估计量(决策树)。早停是一种正则化形式,用于防止训练数据过拟合。

首先对数据进行一次独热编码,以供模型使用。这意味着某些零重要性特征可以通过一键编码来创建。要查看单编码的列,我们可以访问 FeatureSelectorone_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.
复制代码

运行梯度提升模型需要对特征进行独热编码。这些特征保存在 FeatureSelectorone_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
复制代码

FeatureSelectordata 属性保存原始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)
复制代码

111 features required for 0.99 of cumulative importance
复制代码

FeatureSelector中的 feature_importances 属性中可以访问所有的特征重要性。

fs.feature_importances.head(10)
复制代码
featureimportancenormalized_importancecumulative_importance
0EXT_SOURCE_2145.20.0981740.098174
1EXT_SOURCE_3127.70.0863420.184517
2EXT_SOURCE_182.70.0559160.240433
3DAYS_BIRTH71.40.0482760.288709
4DAYS_REGISTRATION64.10.0433400.332049
5DAYS_ID_PUBLISH59.30.0400950.372143
6SK_ID_CURR57.70.0390130.411156
7DAYS_EMPLOYED55.50.0375250.448682
8DAYS_LAST_PHONE_CHANGE47.00.0317780.480460
9AMT_INCOME_TOTAL41.00.0277210.508181

我们可以使用这些结果来仅选择“ ”个最重要的特征。例如,如果我们希望排名前100位的重要性最高,则可以执行以下操作。

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()
复制代码
featureimportancenormalized_importancecumulative_importance
0EXT_SOURCE_2165.30.0910740.091074
1EXT_SOURCE_3154.70.0852340.176309
2EXT_SOURCE_197.50.0537190.230028
3DAYS_BIRTH84.60.0466120.276639
4DAYS_REGISTRATION75.90.0418180.318457

由于特征重要性已更改,因此删除的特征数略有差异。由缺失的(missing)、单一的(single_unique)和共线( collinear)确定要删除的特征数量将保持不变,因为它们是确定性的,但是由于多次训练模型,零重要性( zero_importance )和低重要性(low_importance )的特征数量可能会有所不同。

结论

本笔记本演示了如何使用FeatureSelector类从数据集中删除特征。此实现中有几个重要注意事项:

  • 在机器学习模型的多次运行中,特征重要性将发生变化。

  • 决定是否保留从一个独热编码创建的额外特征。

  • 为不同的参数尝试几个不同的值,以确定哪些参数最适合机器学习任务。

  • 对于相同的参数,缺失的(missing)、单一的(single_unique)和共线( collinear)的输出将保持不变。

  • 特征选择是机器学习工作流中的一个关键步骤,它可能需要多次迭代来优化。

    我很感激你对这个项目的任何评论、反馈或帮助。

    代码和数据下载地址:

    github.com/fengdu78/Da…

参考

WillKoehrsen:github.com/WillKoehrse…

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改