使用sklearn和Pandas进行特征选择
特征选择是执行任何机器学习任务时的首要和重要步骤之一。数据集中的特征表示列。当我们得到机器学习数据集时,不一定每列(特征)都会对输出变量产生影响。如果我们在机器学习模型中添加这些不相关的特征,它将使模型变差(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()
1.Filter方法:
顾名思义,您过滤并仅采用相关特征的子集。选择特征后即可构建模型。这里的过滤是使用相关矩阵完成的,最常用的是Pearson相关。
在这里,我们将首先绘制Pearson相关热图,并查看自变量与输出变量MEDV的相关性。我们只选择具有高于0.5(取绝对值)的相关性的特征与输出变量。
相关系数的值介于-1到1之间
- 接近0的值意味着弱相关性(0表示不相关)
- 接近1的值意味着强正相关
- 接近-1的值意味着强负相关
#Correlation with output variable cor_target = abs(cor["MEDV"]) #Selecting highly correlated features relevant_features = cor_target[cor_target>0.5] relevant_features
我们可以看到,只有特征RM,PTRATIO和LSTAT与输出变量MEDV强相关。因此,我们将删除所有其他特征。线性回归的假设之一是独立变量需要彼此不相关。如果这些变量彼此相关,那么我们只需要保留其中一个变量并丢弃其余变量。因此,让我们检查所选特征之间的相关性。
print(df[["LSTAT","PTRATIO"]].corr()) print(df[["RM","LSTAT"]].corr())
从上面的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
我们可以看到变量'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)
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_)
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))
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)
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)
print("Lasso picked " + str(sum(coef != 0)) + " variables and eliminated the other " + str(sum(coef == 0)) + " variables")
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")
这里的Lasso模型已经采用了除NOX,CHAS和INDUS之外的所有特征。
结论:
我们了解了如何为数值数据使用多种方法选择特征,并比较了它们的结果。现在出现了在什么情况下选择哪种方法的困惑。以下几点将帮助你做出这个决定:
- Filter方法不太准确。它在做EDA时很棒,它也可以用于检查数据中的多重共线性。
- Wrapper和Embedded方法可以提供更准确的结果,但由于它们的计算成本很高,因此这些方法适用于较少的特征(~20)。