如何在Python中实现递归特征消除算法

319 阅读9分钟

开始使用机器学习中的递归特征消除算法

大多数时候,我们在机器学习中使用的数据通常是高维的。因此,在这些数据上实现的模型是 "维度诅咒 "的受害者。

维度诅咒指的是与高维数据集相关的所有问题。例如,当数据集维度过高时,有可能高度详细,因此,一些特征中包含的信息已经被同一数据集中的其他特征所捕获。因此,特征最终是高度相关的。

我们需要明白,我们所讨论的维度是指数据集中的特征数量,而不是实例(行)的数量。

虽然信息越多越好,但当数据包含重复的或高度详细的信息时,我们的机器学习模型的训练速度就会减慢。此外,需要高的处理能力来完成训练过程。

与高维数据集相关的另一个问题是,在这些数据集上训练的模型最终会过度拟合,因此,对数据的概括也很糟糕。从这个讨论中可以看出,高维数据集很可能会产生一个表现不佳的模型。因此,我们需要照顾到这个问题。

为了克服 "维度诅咒 "的问题,我们减少原始数据集的特征数量。这个过程中,得到的新维度空间要比初始维度空间低。与这个新维度空间相关的好处是。

  • 与原始维度空间相比,需要更少的计算能力
  • 易于进行数据可视化
  • 数据中不包含不相关的信息

在这篇文章中,我们将研究用被称为递归特征消除的特征选择技术来减少特征的问题。

前提条件

为了从本材料中获得最大的收益,你需要熟悉以下内容。

  • Python编程知识。
  • [数据集]。

递归特征消除法简介

递归特征消除(RFE)是包裹法,即它可以TA。这种算法适合一个模型,并确定重要的特征如何解释数据集的变化。一旦确定了特征的重要性,它就会在每次迭代中逐一删除那些不太重要的特征。

这些特征被反复消除,直到达到某个阈值(所需的最佳特征数)。首先,让我们了解这个算法在sklearn中是如何工作的。

在高层次上,RFE算法需要两个参数。

  1. Estimator:RFC包裹着任何适应数据的模型,并通过这个参数计算数据集中的特征重要性。如何计算特征重要性取决于传递给RFC类的模型。例如,如果我们给出的模型是一棵决策树,那么特征的重要性将通过对所有特征从最重要到最不重要的排序得到。

另一方面,如果我们拟合一个线性回归模型,特征的重要性将以系数的形式计算。在这种情况下,最重要的系数与数据集中最关键的特征有关,而最小的特征与最不重要的特征有关。主要来说,基于树的模型,如决策树、随机森林等,被用来确定特征的重要性。

从这一节中,我们需要了解,计算特征重要性的模型不一定要与数据集的模型相匹配。

  1. n_features_to_select:我们希望保留的特征数量在这个参数中指定。我们对RFE类的挑战是,要保留的最佳特征数量并不总是事先知道的。

然而,我们在RFE类的顶部运行交叉验证,这将自动确定要保留的最佳特征数量。有了sklearn,我们不需要单独做这个。

相反,sklearn为我们提供了RFECV ,它将RFE与交叉验证一起实现,并自动为我们选择最佳的特征数量。说到这里,我们现在可以继续在Python中实现这个算法了。

在Python中实现RFE算法

数据准备

首先,我们将导入以下库。

# for numeric handling
import numpy as np
# to handle dataframes
import pandas as pd 
# for plotting
import matplotlib.pyplot as plt

我们将在这个实现中使用的数据集可以从先决条件部分提供的链接中下载。

读取数据集

data = pd.read_csv("Data.csv")
# cheack for data shape
data.shape

我们的数据被成功导入。这个数据有1470个实例,34个特征,和一个研究变量。它包含了某一公司的雇员信息。因此,它将决定一个雇员是否会离开该组织或留下。使用head 函数,让我们看一下这个数据集的前五个观察值。

# check for the first five observations of the dataset
data.head()

Output

Attrition 列是我们在上面的数据子集中的研究变量。这一列有两个可能的值,YesNoYes 的值意味着一个员工将很快离开公司,而No 则意味着一个员工不会很快离开公司。因此,这个数据的目的是建立一个模型,预测哪个员工会离开公司,谁会留下来。

然而,由于这个数据集有许多特征;也被称为解释变量;用这些特征建立一个模型可能非常昂贵。在这个数据集上建立的模型对于预期的目的来说可能是非常复杂的。此外,在试图捕捉所有的特征时,模型可能会过度拟合。

为了确保这个问题不发生,我们需要分析我们的特征空间,并选择一个至少能解释数据集中95%方差的特征子集。我们将使用递归特征消除技术来实现这一目标。然而,递归特征消除法的计算成本很高,因此,我们需要尽可能地预处理我们的数据。

让我们在实施RFE模型之前继续进行数据预处理活动,以获得我们的最佳特征子集。

有些特征并不能解释上面数据集中的研究变量。因此,我们需要从我们的数据集中放弃它们。这些列包括。

  • 数据集中的记录数
  • 雇员数(EmployeeCount
  • 雇员人数
  • 超过18小时
  • 标准工时

为了从我们的数据集中删除这些记录,让我们运行下面的代码。

# Removing insgnificant features from the dataset
data = data.drop(["EmployeeCount","EmployeeNumber",
                   "Over18", "StandardHours"], axis=1)
# checking the current number of features
data.shape[1]

输出。

31

与原来的维度不同,我们的数据现在有31列(以前是35列)。所以现在,让我们检查一下数据中是否有缺失值。

# Check for missing values in our dataset and impute them if any
data.isnull().sum().sum()

输出。

0

上述输出的含义是,数据集中没有缺失值。

由于我们将数字数据装入机器学习模型,我们需要检查数据集中是否有任何非数字数据,如果有的话,将其转换为数字数据。

# check for non-numeric data types
data.select_dtypes("object").head(5)

Object data

上述输出显示,我们的31个列中有8个包含非数字数据类型。在这8个列中,我们的研究变量是减员列。

由于我们不会将研究变量拟合到我们未来的估计模型中,目前,我们不会对其进行编码。说到这里,让我们在label encoder 类的帮助下,将其余七列编码为数字数据类型。

# Encoding object data type
from sklearn.preprocessing import LabelEncoder
LbEn = LabelEncoder()
data["BusinessTravel"] = LbEn.fit_transform(data["BusinessTravel"])
data["Department"] = LbEn.fit_transform(data["Department"])
data["EducationField"] = LbEn.fit_transform(data["EducationField"])
data["Gender"] = LbEn.fit_transform(data["Gender"])
data["JobRole"] = LbEn.fit_transform(data["JobRole"])
data["MaritalStatus"] = LbEn.fit_transform(data["MaritalStatus"])
data["OverTime"] = LbEn.fit_transform(data["OverTime"])

# Checking for any remaining object data
data.select_dtypes("object").columns

输出。

Index(['Attrition'], dtype='object')

我们已经成功地对我们的数据进行了编码,现在我们可以把它分成一组特征和研究变量分别进行编码。

X = data.drop(["Attrition"], axis=1)
Y = data["Attrition"]

我们需要检查我们的数据集是否平衡。如果它是平衡的,我们将继续我们的活动,如果不是,那么我们将平衡它。因此,让我们运行下面的代码并检查一下。

data["Attrition"].value_counts()

输出。

No     1233
Yes     237
Name: Attrition, dtype: int64

从这个输出中,我们的数据有1233个 "否 "和237个 "是 "的观察值。从这个输出中可以看出,我们的数据是非常不平衡的。因此,我们需要对其进行平衡。为了做到这一点,我们使用smoteen 抽样技术。

from imblearn.combine import SMOTEENN
smtn = SMOTEENN(random_state = 0)
# Training the model
smtn.fit(X,Y)
# Making samples
X, Y = smtn.fit_resample(X,Y)
Y.value_counts()

一旦上面的代码被执行,它将返回。

Yes    814
No     774
Name: Attrition, dtype: int64

从上面的输出结果来看,是和非两类之间的差异是最小的。因此,我们的数据是平衡的。现在,我们可以将我们的数据分成训练集和测试集。

from sklearn.model_selection import train_test_split
XTrain, XTest, YTrain, YTest = train_test_split(X,Y, test_size=0.2, random_state=0)

我们的数据现在已经准备好实现RFE算法了。

实施RFE算法

我们的估计器将是一棵决策树,因此我们应将我们的数据装入决策树。

from sklearn.feature_selection import RFECV
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier()
rfecv = RFECV(estimator= model, step = 1, cv = 5, scoring="accuracy")
rfecv = rfecv.fit(XTrain, YTrain)

print("The optimal number of features:", rfecv.n_features_)
print("Best features:", XTrain.columns[rfecv.support_])

执行上面的代码,我们得到。

The optimal number of features: 3
Best features: Index(['JobLevel', 'MonthlyIncome', 'MonthlyRate'], dtype='object')
/usr/local/lib/python3.7/dist-packages/sklearn/base.py:446: UserWarning: X does not have valid feature names, but RFECV was fitted with feature names
  "X does not have valid feature names, but"

上面的输出显示,最佳的特征数量是三个。因此,在原始数据集的35个特征中,它们所携带的信息被捕获在三个特征中。这些特征在上面的输出中被返回,即JobLevel、月收入和月率。

如果我们在这些特征上训练我们的预测模型,在训练过程中所需要的时间和处理能力要比我们在原始数据集的所有35个特征上训练模型要少得多。因此,模型遭受过度拟合的几率会降低得更多。

总结

这篇文章解释了如何在Python中实现递归特征消除算法。在实现这个模型之前,我们讨论了为什么必须降低数据集的维度,后来我们看了用递归特征消除算法选择特征。我希望这篇文章能帮助你了解RFE算法。