使用sklearn和Pandas进行特征选择

CYJ0go 2019-02-11

特征选择是执行任何机器学习任务时的首要和重要步骤之一。数据集中的特征表示列。当我们得到机器学习数据集时,不一定每列(特征)都会对输出变量产生影响。如果我们在机器学习模型中添加这些不相关的特征,它将使模型变差(Garbage In Garbage Out)。这就需要进行特征选择。

在Pandas中实现特征选择时,数值特征和分类特征是不同的。在这里,我们将首先讨论数字特征选择。因此,在实现以下方法之前,我们需要确保DataFrame仅包含数字特征。此外,本文还将讨论回归问题的方法,即输入变量和输出变量都是连续的。

特征选择可以通过多种方式完成,大致有3类:

  • Filter方法
  • Wrapper方法
  • Embedded方法

关于数据集:

我们将使用内置的Boston数据集,可以通过sklearn加载。我们将使用上面列出的方法为预测“MEDV”列的回归问题选择特征。在以下Python代码中,我们将导入所有必需的Python库并加载机器学习数据集。

#importing libraries
from sklearn.datasets import load_boston
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.api as sm
%matplotlib inline
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
from sklearn.linear_model import RidgeCV, LassoCV, Ridge, Lasso
#Loading the dataset
x = load_boston()
df = pd.DataFrame(x.data, columns = x.feature_names)
df["MEDV"] = x.target
X = df.drop("MEDV",1) #Feature Matrix
y = df["MEDV"] #Target Variable
df.head()

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

1.Filter方法:

顾名思义,您过滤并仅采用相关特征的子集。选择特征后即可构建模型。这里的过滤是使用相关矩阵完成的,最常用的是Pearson相关。

在这里,我们将首先绘制Pearson相关热图,并查看自变量与输出变量MEDV的相关性。我们只选择具有高于0.5(取绝对值)的相关性的特征与输出变量。

相关系数的值介于-1到1之间

  • 接近0的值意味着弱相关性(0表示不相关)
  • 接近1的值意味着强正相关
  • 接近-1的值意味着强负相关

使用sklearn和Pandas进行特征选择

#Correlation with output variable
cor_target = abs(cor["MEDV"])
#Selecting highly correlated features
relevant_features = cor_target[cor_target>0.5]
relevant_features

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

我们可以看到,只有特征RM,PTRATIO和LSTAT与输出变量MEDV强相关。因此,我们将删除所有其他特征。线性回归的假设之一是独立变量需要彼此不相关。如果这些变量彼此相关,那么我们只需要保留其中一个变量并丢弃其余变量。因此,让我们检查所选特征之间的相关性。

print(df[["LSTAT","PTRATIO"]].corr())
print(df[["RM","LSTAT"]].corr())

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

从上面的Python代码可以看出,变量RM和LSTAT彼此强相关(-0.613808)。因此,我们只保留一个变量而丢弃另一个变量。我们将保留LSTAT,因为它与MEDV的相关性高于RM。

在放弃RM之后,我们留下了两个特征,LSTAT和PTRATIO。这些是Pearson相关性给出的最终特征。

2.Wrapper方法:

Wrapper方法需要一种机器学习算法,并将其性能作为评价标准。这意味着,您将这些特征提供给所选的机器学习算法,并根据机器学习模型性能添加/删除这些特征。这是一个迭代的和计算昂贵的过程,但它比Filter方法更准确。

有不同的Wrapper方法,如后向消除(Backward Elimination),前向选择(Forward Selection),双向消除(Bidirectional Elimination)和RFE。我们将在这里讨论后向消除和RFE。

后向消除

顾名思义,我们首先将所有可能的特征提供给模型。我们检查模型的性能,然后逐个迭代地删除性能最差的特征,直到模型的整体性能达到可接受的范围。

此处用于评估特征性能的性能指标是pvalue。如果pvalue高于0.05,那么我们删除该特征,否则我们保留它。

我们将首先在这里运行一次迭代,这只是得到一个概念的想法,然后我们将在循环中运行相同的代码,这将给出最终的一组特征。在这里我们使用OLS模型代表“普通最小二乘法”。该模型用于执行线性回归。

#Adding constant column of ones, mandetory for sm.OLS model
X_1 = sm.add_constant(X)
#Fitting sm.OLS model
model = sm.OLS(y,X_1).fit()
model.pvalues

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

我们可以看到变量'AGE'的最高p值为0.9582293,大于0.05。因此,我们将删除此特征并再次构建机器学习模型。这是一个迭代过程。这种方法在下面实现,它将给出最终的变量集,即CRIM,ZN,CHAS,NOX,RM,DIS,RAD,TAX,PTRATIO,B和LSTAT。

#Backward Elimination
cols = list(X.columns)
pmax = 1
while (len(cols)>0):
 p= []
 X_1 = X[cols]
 X_1 = sm.add_constant(X_1)
 model = sm.OLS(y,X_1).fit()
 p = pd.Series(model.pvalues.values[1:],index = cols) 
 pmax = max(p)
 feature_with_p_max = p.idxmax()
 if(pmax>0.05):
 cols.remove(feature_with_p_max)
 else:
 break
selected_features_BE = cols
print(selected_features_BE)

使用sklearn和Pandas进行特征选择

Output:

['CRIM', 'ZN', 'CHAS', 'NOX', 'RM', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT']

RFE(递归特征消除)

递归特征消除(RFE)方法通过递归地移除属性并在剩余的属性上构建模型来工作。它使用精度度量来根据特征的重要性对特征进行排名。RFE方法将要使用的模型和所需特征的数量作为输入。然后它给出了所有变量的排名,1是最重要的。True是相关特征而False是不相关特征。

model = LinearRegression()
#Initializing RFE model
rfe = RFE(model, 7)
#Transforming data using RFE
X_rfe = rfe.fit_transform(X,y) 
#Fitting the data to model
model.fit(X_rfe,y)
print(rfe.support_)
print(rfe.ranking_)

使用sklearn和Pandas进行特征选择

Output:

[False False False True True True False True True False True False True]

[2 4 3 1 1 1 7 1 1 5 1 6 1]

这里我们采用了具有7个特征的LinearRegression模型,RFE给出了如上所述的特征排名,但是数字'7'的选择是随机的。现在我们需要找到最佳数量的特征(其准确度最高)。我们通过usig循环从1个特征开始,然后到13个。然后我们选择准确度最高的那个。

#no of features
nof_list=np.arange(1,13) 
high_score=0
#Variable to store the optimum features
nof=0 
score_list =[]
for n in range(len(nof_list)):
 X_train, X_test, y_train, y_test = train_test_split(X,y, test_size = 0.3, random_state = 0)
 model = LinearRegression()
 rfe = RFE(model,nof_list[n])
 X_train_rfe = rfe.fit_transform(X_train,y_train)
 X_test_rfe = rfe.transform(X_test)
 model.fit(X_train_rfe,y_train)
 score = model.score(X_test_rfe,y_test)
 score_list.append(score)
 if(score>high_score):
 high_score = score
 nof = nof_list[n]
print("Optimum number of features: %d" %nof)
print("Score with %d features: %f" % (nof, high_score))

使用sklearn和Pandas进行特征选择

Output:

Optimum number of features: 10

Score with 10 features: 0.663581

从上面的Python代码可以看出,最佳的特征数量为10.我们现在将10个特征数量提供给RFE,并获得RFE方法给出的最终特征集,如下所示:

cols = list(X.columns)
model = LinearRegression()
#Initializing RFE model
rfe = RFE(model, 10) 
#Transforming data using RFE
X_rfe = rfe.fit_transform(X,y) 
#Fitting the data to model
model.fit(X_rfe,y) 
temp = pd.Series(rfe.support_,index = cols)
selected_features_rfe = temp[temp==True].index
print(selected_features_rfe)

使用sklearn和Pandas进行特征选择

Output:

Index(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'DIS', 'RAD', 'PTRATIO', 'LSTAT'], dtype='object')

3.Embedded方法

Embedded方法在某种意义上是迭代的,它负责模型训练过程的每次迭代,并仔细提取对特定迭代的训练贡献最大的那些特征。正则化方法是最常用的Embedded方法,其在给定系数阈值的情况下惩罚特征。

在这里,我们将使用Lasso正则化进行特征选择。如果该特征无关紧要,则套索会对其系数进行处罚并使其为0.因此,系数= 0的特征将被删除。

reg = LassoCV()
reg.fit(X, y)
print("Best alpha using built-in LassoCV: %f" % reg.alpha_)
print("Best score using built-in LassoCV: %f" %reg.score(X,y))
coef = pd.Series(reg.coef_, index = X.columns)

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

print("Lasso picked " + str(sum(coef != 0)) + " variables and eliminated the other " + str(sum(coef == 0)) + " variables")

使用sklearn和Pandas进行特征选择

imp_coef = coef.sort_values()
import matplotlib
matplotlib.rcParams['figure.figsize'] = (8.0, 10.0)
imp_coef.plot(kind = "barh")
plt.title("Feature importance using Lasso Model")

使用sklearn和Pandas进行特征选择

使用sklearn和Pandas进行特征选择

这里的Lasso模型已经采用了除NOX,CHAS和INDUS之外的所有特征。

结论:

我们了解了如何为数值数据使用多种方法选择特征,并比较了它们的结果。现在出现了在什么情况下选择哪种方法的困惑。以下几点将帮助你做出这个决定:

  1. Filter方法不太准确。它在做EDA时很棒,它也可以用于检查数据中的多重共线性。
  2. Wrapper和Embedded方法可以提供更准确的结果,但由于它们的计算成本很高,因此这些方法适用于较少的特征(~20)。

相关推荐