什么是特征选择?为什么它很重要?

什么是特征选择?为什么它很重要?

在本文中,我们将讨论特征选择技术,并回答为什么它很重要以及如何在实践中使用该技术。如果你想了解更多关于数据科学的相关内容,可以阅读以下这些文章:
大部分数据科学课程没有教给你的内容
数据科学面试中你应该知道的10个高级SQL概念
数据科学家/分析师应该避免的5大编程错误
数据科学算法如何将商业计划变现?

本文将帮助你解决以下面试中遇到的问题:

  1. 什么是特征选择?
  2. 说出特征选择的好处?
  3. 你知道哪些特征选择技巧?
  4. 区分单变量、双变量和多变量分析。
  5. 我们能用PCA来进行特征选择吗?
  6. 前向特征选择和后向特征选择的区别是什么?

什么是特征选择?为什么它很重要?

特征选择是选择与你的ML模型更加一致、非冗余和相关的基本特征的过程。在ML项目中使用特征选择是必要的,因为:

  • 它有助于减少数据集的大小和复杂性,反过来使我们可以用更少的时间来训练模型,更少的计算成本来训练ML模型和进行推理;
  • 具有较少特征的简单ML模型更容易理解和解释;
  • 它可以避免过拟合。因为特征越多,模型就越复杂,这就带来了维数的麻烦(错误会随着特征数量的增加而增加)

特征选择方法有哪些?

有两种常用的方法可以进行特征选择:

  1. 前向特征选择。使用这种方法,你开始用一个特征(或一个小子集)拟合模型,并不断添加特征,直到对ML模型指标没有影响为止。你可以使用相关分析(例如,基于皮尔逊系数)等方法,也可以从单个特征或特征子集开始拟合模型。
  2. 后向特征选择。这是与前向特征选择相反的方法。使用这种方法,你可以从完整的特征集开始,然后只要ML模型度量保持不变,就可以逐一迭代地减少特征。

特征选择的方法有:过滤法、包装法、嵌入法

  • 过滤法:按照发散性或者相关性对各个特征进行评分,通过设定阈值或者待选择阈值的个数来选择特征。
  • 包装法:根据目标函数(通常是预测效果评分)每次选择若干特征,或者排除若干特征。
  • 嵌入法:使用机器学习的某些算法或模型进行训练,得到各个特征的权值系数,并根据系数从大到小选择特征。

在本文中,我们将使用以下策略:

  1. 我们从了解特征开始,并与业务相关方讨论如何进行特征选择。
  2. 然后我们识别高度相关的特征以避免多重共线性。
  3. 并基于filtred和wrapper方法查找特征和目标变量之间的相关性。
  4. 最后,我们深入研究最相关的特征以获得额外的业务洞察力。

Python实例

值得注意的是,我们将使用包含以往贷款申请人数据的fintech数据集,如信用等级、申请人收入、DTI和其他特征。最终目标是确定模型并使用ML预测贷款申请人是否可能违约(未能支付贷款),这有助于银行做出决策,例如拒绝贷款申请、减少贷款金额或以较高利率向风险申请人贷款。你可以在此处了解有关数据集的更多信息。

我用来运行代码的环境是Kaggle。如果你以前从未使用过Kaggle,我建议你阅读本文。

让我们开始并加载数据集:

#load packages and set pd formats %matplotlib inline
from matplotlib import pyplot as plt pd.set_option('display.float_format', lambda x: '%.0f' % x) #load dataset loan = pd.read_csv('../input/lending-club/accepted_2007_to_2018Q4.csv.gz', compression='gzip', low_memory=True) loan.info

我们观察到,数据集包含200多万行,我们称之为观测值,以及150多个特征值。这是一个相当大的数据量,通常有很多“噪音”,对我们的ML工作没有帮助,因此我们需要在ML进行训练之前验证数据的质量和适用性。

首先,咨询业务利益相关者。

对如此详尽的特征列表进行分析可能需要大量的计算资源和时间。通常,你的业务相关人员将详细了解每个数据集的属性。

咨询并询问他们哪些特征是必需的;例如,在fintech数据集的示例中,你可能需要咨询每天执行贷款评估的贷款专员。贷款专员将确切地知道是什么驱动了他们的决策过程(你希望使用ML将其自动化)

让我们想象一下,我们已经采取了这一步骤,并收到了以下建议(请参阅下面的代码片段)

#consider only business critical features loans = loan[['id', 'loan_amnt', 'term','int_rate', 'sub_grade', 'emp_length','grade', 'annual_inc', 'loan_status', 'dti', 'mths_since_recent_inq', 'revol_util', 'bc_open_to_buy', 'bc_util', 'num_op_rev_tl']] #remove missing values
loans = loans.dropna()

花一些时间来了解数据集中每个特征的含义:

  • loan_amnt-借款人申请的贷款金额。
  • term-贷款的付款数量,其中金额以月为单位,可以是36或60。
  • int_rate-贷款利率。
  • sub_grade-贷款细分级别
  • emp_length-借款的雇佣年限(以年为单位)
  • home_ownership-借款人提供的居住状态(自有,按揭,租住)
  • annual_inc-借款人提供的自报年度收入
  • addr_state-借款人在贷款申请中提供的地址
  • dti-贷款占收入比例。
  • revol_util-透支额度占信用比例。
  • bc_util-所有银行卡账户的总余额与信用限额的比率
  • num_op_rev_tl-未结贷款账户数
  • loan_status-当前贷款状态(例如,已全额付清或已注销)。这是我们将用模型预测的标签。

在进行任何进一步的工作之前,执行数据处理步骤。准备步骤包括缺失值、异常值和分类特征处理。

#preprocessing
#remove missing values loans = loans.dropna() #remove outliers q_low = loans["annual_inc"].quantile(0.08)
q_hi = loans["annual_inc"].quantile(0.92) loans = loans[(loans["annual_inc"] < q_hi) & (loans["annual_inc"] > q_low)]
loans = loans[(loans['dti'] <=45)]
q_hi = loans['bc_open_to_buy'].quantile(0.95)
loans = loans[(loans['bc_open_to_buy'] < q_hi)]
loans = loans[(loans['bc_util'] <=160)]
loans = loans[(loans['revol_util'] <=150)]
loans = loans[(loans['num_op_rev_tl'] <=35)] #categorical features processing
cleaner_app_type = {"term": {" 36 months": 1.0, " 60 months": 2.0},
     "sub_grade": {"A1": 1.0, "A2": 2.0, "A3": 3.0, "A4": 4.0,
          "A5": 5.0, "B1": 11.0, "B2": 12.0, "B3": 13.0, "B4": 14.0,
          "B5": 15.0, "C1": 21.0, "C2": 22.0, "C3": 23.0, "C4":
          24.0, "C5": 25.0, "D1": 31.0, "D2": 32.0, "D3": 33.0,
          "D4": 34.0, "D5": 35.0, "E1": 41.0, "E2": 42.0, "E3":
          43.0, "E4": 44.0, "E5": 45.0, "F1": 51.0, "F2": 52.0,
          "F3": 53.0, "F4": 54.0, "F5": 55.0, "G1": 61.0, "G2":
          62.0, "G3": 63.0, "G4": 64.0, "G5": 65.0, },
      "emp_length": {"< 1 year": 0.0, '1 year': 1.0, '2 years': 2.0,
          '3 years': 3.0, '4 years': 4.0, '5 years': 5.0, '6 years':
           6.0, '7 years': 7.0, '8 years': 8.0, '9 years': 9.0, '10+
           years': 10.0 }
       }
loans = loans.replace(cleaner_app_type)

预选特征后,下一步是部署单变量分析。当你分析单个特征时,你可以使用的最常见的两种技术是:

  1. 删除低方差特征。
  2. 删除包含大量缺失值的特征。

低方差。假设你有两个特征:

  1. 性别只包含一个性别值(例如女性)
  2. 年龄包含30到50岁之间的不同值。在这种情况下,性别特征的方差较小,因为该属性中的值都相同,并且在模型训练阶段,它不会帮助模型找到任何模式;因此,你可以删除此特征。

实现很简单,你可以使用sklearn Variance Threshold函数。下面的代码将标识至少90%的实例中相同的特征。

from sklearn.feature_selection import VarianceThresholdvariance = VarianceThreshold(threshold = (.9 * (1 - .9))) variance.fit(loans) variance.get_support()

在我们的例子中没有低方差特征,我们不需要删除任何东西。

缺失值。我们没有在这组特征中包含大量缺失值的任何特征;因此,我们跳过这一步。我建议你阅读本文,了解如何处理缺失值并识别它们的更多信息。

第二步,确定高度相关的特征。

第二步涉及特征多重共线性。在开始之前,请注意,我们将在第2步和第3步中使用双变量分析。我们使用二变量分析来确定两组变量之间是否存在关系(相关性)

利用这些相关性,你可以获得如下结论:

  • 一个或多个变量依赖于另一个可能导致多重共线性的变量;
  • 存在因果关系的标识,其中相关性有助于从一个变量预测另一个变量;
  • 获得业务层面的见解,了解导致标签结果的因素,在我们的案例中,每个特征如何影响贷款支付结果。

当数据集在特征之间具有较高的正相关性或负相关性时,ML模型可能会受到多重共线性的影响。高度相关的特征可能提供相同的信息,这使得它们成为冗余。在这种情况下,它可能会导致歪曲或误导的结果,为了解决这个问题,我们可以只保留一个特征,并删除冗余特征,而不会丢失任何信息。

例如,月薪和年薪;虽然它们可能不完全相同,但它们可能具有相同的模式。像逻辑回归和线性回归这样的模型对这个问题很敏感,如果用这些冗余特征训练模型,可能会产生误导性的结果。因此,你应该致力于消除其中之一。

注意:决策树和增强树算法不受多重共线性的影响(参考文献)

如何处理多重共线性?

有很多方法可以解决这个问题。检测高度相关特征的最简单方法是使用Pearson相关性并删除其中一个完全相关(约90%)的特征。主成分分析(PCA)作为多元统计分析的一种常用方法,在处理多变量问题时具有其一定的优越性,其降维的优势是明显的,主成分回归方法对于一般的多重共线性问题还是适用的,尤其是对共线性较强的变量之间。

我们将应用相关技术,在这种情况下,pandas_profiling将帮助我们。请参阅下面的代码以生成pandas报告。

如果你向下滚动到报告的末尾,你会发现两个部分——“交互”和“相关性”。相关性将帮助你快速找出变量之间的关系。

from pandas_profiling import ProfileReport
profile = ProfileReport (loans, title = 'Loans Defaults Prediction', html = {'style': {'full_width': True }}) profile
Pandas分析的相关屏幕截图

你会发现从Pearson到Phik的不同类型的相关性。当你有尚未处理的分类特征时,Phik会派上用场。例如,我们有下面的“等级”分类特征,它很好地绘制在相关矩阵上:

Phink的Pandas分析关联截图

如何读取矩阵:请注意,可能的相关性范围是从+1到-1,其中:

  • 零相关性表明变量之间没有关系;
  • 相关系数-1表示完全负相关,即当一个变量上升时,另一个变量下降;
  • 相关性为+1表示完全正相关,这意味着两个变量一起朝着同一方向移动。
  • 我们可以观察到以下高度相关的特征:
  • 客户特征。bc_open_to_buy/num_op_rev_tl。这两个特征都与循环账户和银行卡有关,因此它们高度相关。为了避免多重共线性问题,让我们在初始模型中去掉bc_open_To_buy特征。revol_util/bc_util。这是一个类似的情况,我们可以删除bc_util特征。
  • 贷款特征信息。Int_rate和grade是sub_grade的衍生产品;因此,它们高度相关;让我们删除这些。term、sub_grade和loan_amount也相互关联,但较小,所以保留它们。

删除这些特征:

loans.drop(["bc_util", "bc_open_to_buy","int_rate", "grade"], axis = 1, inplace = True)

第三步,找出特征和目标变量之间的相关性。

现在,我们希望看到与目标变量高度相关的特征,在我们的例子中是loan_status。我们将回顾两种流行的方法:过滤法(Filter)和包装法(Wrapper)

过滤法

与我们在上一节中所做的类似,我们将使用过滤法。相关矩阵将帮助我们识别高度相关的特征。请注意,有时pandas profiling报告的生成需要时间,因此了解绘制相关矩阵的其他技术至关重要。这里还有两种方法:

loans_cor=loan.corr()
loans_cor
代码输出
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(10,6))
sns.heatmap(loans_cor, annot=True)
代码输出

我们可以观察到以下高度相关的特征:sub_grade, term, loan_amnt, dti, emp_length, annual_inc 以及他的 loan_status。

这让我们很好地了解了哪些特征是重要的。

包装法

或者,我们可以使用包装器,这是一种更自动化的特征选择方法,可以基于:

  1. 前向特征选择
  2. 后向特征选择
  3. 双向特征选择

在本文中,我们将使用Python内置函数SequentialFeatureSelector()实现前向特征选择,该函数是mlxtend库的一部分。此函数具有不同的特征选择技术。

SequentialFeatureSelector()有11个参数,你可以调整这些参数以获得最佳结果(你可以在此处找到更多信息)。我们将调整以下参数:

  1. Estimator ——这是我们核心使用的算法;在我们的例子中,我们将使用LogisticRegression()算法;
  2. k_features—希望算法选择为最佳特征的特征数量(默认值为1)。它应该少于数据集的所有特征数。注意,该包还提供了“最佳”选项,其中选择器返回最佳的交叉验证性能。因此,你可以应用“最佳”特征,而不是猜测需要返回多少特征;
  3. Forward和floating参数用于标识包装器方法:例如,对于我们的正向选择,它将为Forward=True,而floating=False;
  4. 评分指定了评估标准-由于数据集不平衡,我们对分类器使用sklearn评分度量“精度”。请注意,精度度量是默认度量,但它还包括分类操作的 f1, precision, recall, roc_auc等度量,以及回归任务的r2 , mean_absolute_error, mean_squared_error/neg_mean_squared_error, median_absolute_error等度量;
  5. cv-是交叉验证,默认值为5。

现在,让我们将上述定义的特征选择器放入我们的数据集中。

在给定的数据上,我们将尝试一种非常强大和流行的算法——Logistic Regression with SequentialFeatureSelector。Loan_status将用作预测标签,其余特征将用于查找预测的依赖项。让我们把它们分开:

from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
from sklearn.preprocessing import MinMaxScaler X = loans.drop('loan_status', axis=1)
y = loans[['loan_status']]
y = y.values.ravel() X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y) scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

下一步,我们将使用SequentialFeatureSelector查找“最佳”特征:

#importing the necessary libraries
from mlxtend.feature_selection import SequentialFeatureSelector as SFS # Sequential Forward Selection(sfs)
sfs = SFS(LogisticRegression(),
          k_features='best',
          forward=True,
          floating=False,
          scoring = 'precision',
          cv = 0)

我们需要使用上述代码在贷款数据集上定义特征选择器:

sfs.fit(X, y)
sfs.k_feature_names_

现在,我们可以返回并查看用于ML任务的最佳特征:

代码输出

我们可以通过比较每个训练步骤中的性能和特征数量来了解选择过程。此外,我们可以看到,在迭代步骤中,所选的模型度量没有发生显著变化。

from mlxtend.plotting import plot_sequential_feature_selection as plot_sfs
import matplotlib.pyplot as plt fig1 = plot_sfs(sfs.get_metric_dict(), kind='std_dev') plt.title('Sequential Forward Selection')
plt.grid() plt.show()
代码输出

在本文中,我们了解了特征选择技术的基础知识。然而,在最深层次上理解重要特征和结果变量之间的相关性是非常重要的。请参阅本文,它解释了实现这一目标所需的最后一步。你还可以订阅我们的YouTube频道,观看大量大数据行业相关公开课:https://www.youtube.com/channel/UCa8NLpvi70mHVsW4J_x9OeQ;在LinkedIn上关注我们,扩展你的人际网络!https://www.linkedin.com/company/dataapplab/

原文作者:Maria Gusarova
翻译作者:Chuang Zhang
美工编辑:过儿
校对审稿:过儿
原文链接:https://medium.com/@data.science.enthusiast/feature-selection-techniques-forward-backward-wrapper-selection-9587f3c70cfa