1. 获取数据
2. 数据预处理
数据预处理的目的:让数据适应模型,匹配模型的需求
3. 特征工程
可能面对的问题有:特征之间有相关性,特征和标签无关,特征太多或太小,或者干脆就无法表现出应有的数 据现象或无法展示数据的真实面貌 特征工程的目的: 1) 降低计算成本, 2) 提升模型上限 4. 建模,测试模型并预测出结果 5. 上线,验证模型效果 模块 preprocessing :几乎包含数据预处理的所有内容 模块 Impute :填补缺失值专用 模块 feature_selection :包含特征选择的各种方法的实践 模块 decomposition :包含降维算法 数据预处理 Preprocessing & Impute 2.1 数据无量纲化 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“ 无量纲化 ” 。 数据的无量纲化可以是线性的,也可以是非线性的。线性的无量纲化包括 中心化 ( Zero-centered 或者 Mean-subtraction)处理和 缩放处理 ( Scale )。中心化的本质是让所有记录减去一个固定值,即让数据样本数据平移到某个位置。缩放的本质是通过除以一个固定值,将数据固定在某个范围之中,取对数也算是一种缩放处理. preprocessing.MinMaxScalerfrom sklearn.proprecessing import MinMaxScaler data=[[-1,2],[-0.5,6],[0,10],[1,18]] scaler=MinMaxScaler(feature_range=[0,1])#实例化 默认值是0-1 取默认值可以不写feature_range scaler=scaler.fit(data)#这里本质上是生成min(x)和max(x) result=scaler.transform(data)#通过接口导出 #一步操作:result=MinMaxScaler(feature_range=[0,1]).fit_transform(data) scaler.inverse_transform(result)#逆转归一化结果 #当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了我计算不了 #此时使用partial_fit作为训练接口 #scaler = scaler.partial_fit(data)使用numpy来实现归一化
import numpy as np X=np.array([[-1,2],[-0.5,6],[0,10],[1,18]]) 归一化 X_nor=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0)) 逆转归一化 X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0)preprocessing.StandardScaler
from sklearn.preprocessing import StandardScaler data=[[-1,2],[-0.5,6],[0,10],[1,18]] scaler=StandardScaler() scaler=scaler.fit(data)#这里本质上时生成均值和方差 fit只能传入二维数据 scaler.mean_#查看每列均值的属性mean_ scaler.var_#查看每列方差的属性var_ x_std=scaler.transform(data)#通过接口导出结果 x_std.mean()#整个数据的均值 x_std.std()#整个数据的标准差 scaler.fit_transform(data)#一部导出结果 scaler.inverse_transform(x_std)#逆转标准化对于 StandardScaler 和 MinMaxScaler 来说,空值 NaN 会被当做是缺失值,在 fifit 的时候忽略,在 transform 的时候保持缺失NaN 的状态显示。并且,尽管去量纲化过程不是具体的算法,但在 fifit 接口中,依然只允许导入至少二维数组,一维数组导入会报错。通常来说,我们输入的X 会是我们的特征矩阵,现实案例中特征矩阵不太可能是一维所以不会存在这个问题。 缺失值处理
使用sklearn.impute 中的SimpleImputer进行填补
import pandas as pd
data=pd.read_csv("./Narrativedata.csv",index_col=0)#index_col=0表示第一列是索引,不取第一列
data.head()
data.loc[:,"Age"]#loc函数是用索引的名字来取值,Series类型
Age=data.loc[:,"Age"].values.reshape(-1,1)#取出所有的值j,将数据升维
from sklearn.impute import SimpleImputer
imp_mean=SimpleImputer()#实例化,默认用均值
imp_median=SimpleImputer(strategy="median")
imp_0=SimpleImputer(strategy="constant",fill_value=0)
imp_mean=imp_mean.fit_transform(Age)
imp_median=imp_median.fit_transform(Age)
imp_0=imp_0.fit_transform(Age)
data.loc[:,"Age"]=imp_median
#现实工作中缺失两条数据可以直接删除 没必要进行填补
Embarked=data.loc[:,"Embarked"].values.reshape(-1,1)
imp_mode=SimpleImputer(strategy="most_frequent").fit_transform(Embarked)
data.loc[:,"Embarked"]=imp_mode
data.info()
使用pandas和numpy进行处理(更简单)
#利用pandas和numpy处理数据
import pandas as pd
data=pd.read_csv("./Narrativedata.csv",index_col=0)
data.head()
data.loc[:,"Age"]=data.loc[:,"Age"].fillna(data.loc[:,"Age"].median())
data.dropna(axis=0,inplace=True)
#删除所有有缺失值的行,如果inplace=False可以使用data_=data_.dropna(axis=0,inplace=False)
2.3 处理分类型特征:编码与哑变量
在机器学习中,大多数算法,譬如逻辑回归,支持向量机
SVM
,
k
近邻算法等都只能够处理数值型数据,不能处理文字,在sklearn
当中,除了专用来处理文字的算法,其他算法在
fifit
的时候全部要求输入数组或矩阵,也不能够导入文字型数据(其实手写决策树和普斯贝叶斯可以处理文字,但是sklearn
中规定必须导入数值型)。
然而在现实中,许多标签和特征在数据收集完毕的时候,都不是以数字来表现的。比如说,学历的取值可以是
["
小 学"
,
“
初中
”
,
“
高中
”
,
"
大学
"]
,付费方式可能包含
["
支付宝
"
,
“
现金
”
,
“
微信
”]
等等。在这种情况下,为了让数据适应算法和库,我们必须将数据进行编码
,即是说,
将文字型数据转换为数值型
。
preprocessing.LabelEncoder
:标签专用,能够将分类转换为分类数值
from sklearn.proprecessing import LabelEncoder y=data.iloc[:,-1] #要输入的是标签,不是矩阵所以允许是一维的 le=LabelEncoder() result=le.fit_transform(y) le.classes_ #属性.classes_查看标签中究竟有多少类别 le.inverse_transform(result) #使用inverse_transform可以逆转 data.iloc[:,-1]=result #如果不需要教学展示的话我会这么写: from sklearn.preprocessing import LabelEncoder data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])preprocessing.OrdinalEncoder :特征专用,能够将分类特征转换为分类数值
from sklearn.preprocessing import OrdinalEncoder #接口categories_对应LabelEncoder的接口classes_,一模一样的功能 data_ = data.copy() data_.head() OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_ data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1]) data_.head()preprocessing.OneHotEncoder :独热编码,创建哑变量 我们刚才已经用 OrdinalEncoder 把分类变量 Sex 和 Embarked 都转换成数字对应的类别了。在舱门 Embarked 这一 列中,我们使用[0,1,2] 代表了三个不同的舱门,然而这种转换是正确的吗? 我们来思考三种不同性质的分类数据: 1 ) 舱门( S , C , Q ) 三种取值 S , C , Q 是相互独立的,彼此之间完全没有联系,表达的是 S≠C≠Q 的概念。这是名义变量。 2 ) 学历(小学,初中,高中) 三种取值不是完全独立的,我们可以明显看出,在性质上可以有高中 > 初中 > 小学这样的联系,学历有高低,但是学 历取值之间却不是可以计算的,我们不能说小学 + 某个取值 = 初中。这是有序变量。 3 ) 体重( >45kg , >90kg , >135kg ) 各个取值之间有联系,且是可以互相计算的,比如 120kg - 45kg = 90kg ,分类之间可以通过数学计算互相转换。这 是有距变量。 然而在对特征进行编码的时候,这三种分类数据都会被我们转换为 [0,1,2] ,这三个数字在算法看来,是连续且可以 计算的,这三个数字相互不等,有大小,并且有着可以相加相乘的联系。所以算法会把舱门,学历这样的分类特 征,都误会成是体重这样的分类特征。这是说,我们把分类转换成数字的时候,忽略了数字中自带的数学性质,所 以给算法传达了一些不准确的信息,而这会影响我们的建模。 类别 OrdinalEncoder 可以用来处理有序变量,但对于名义变量,我们只有使用哑变量的方式来处理,才能够尽量 向算法传达最准确的信息:
from sklearn.processing import oneHotEncoder X=data.iloc[:,1:-1] enc=oneHotEncoder(categories='auto').fit(X) result=enc.transform(X).toarray()#生成的是一个稀疏矩阵 enc.inverse_transform(result) 一步操作 result=oneHotEncoder(categories="auto").fix_transform(X).toarray()#生成的是一个稀疏矩阵 enc.get_feature_names() 求出独热编码后,将独热编码链接,删除原列 newdata=pd.concat([data,pd.Dataframe(result)],axis=1) newdata.drop(["Sex","Embarked"],axis=1,inplace=True) 重现设置列名 newdata.columns=["Age","Survived",'Female', 'Male', 'Embarked_C', 'Embarked_Q', 'Embarked_S']2.4 处理连续型特征:二值化与分段 根据阈值将数据二值化(将特征值设置为 0 或 1 ),用于处理连续型变量。大于阈值的值映射为 1 ,而小于或等于阈 值的值映射为0 。默认阈值为 0 时,特征中所有的正值都映射到 1 。二值化是对文本计数数据的常见操作,分析人员 可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤
#将年龄二值化 from sklearn.proprecessing import Binarizer X=data.iloc[:,0].values.reshape(-1,1)#特征不能使用一维数组 transformer=Binarizer(threshold=30).fit_transform(X) data.iloc[:,0]=transformerpreprocessing.KBinsDiscretizer
from sklearn.proprecessing import KBinsDiscretizer X=data.iloc[:,0].values.reshape(-1,1) est=KBinsDiscretizer(n_bins=3,encode="ordinal",strategy="uniform") result=est.fit_transform(X) data.iloc[:,0]=result est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform') #查看转换后分的箱:变成了哑变量 est.fit_transform(X).toarray()特征选择 feature_selection 当数据预处理完成后,我们就要开始进行特征工程了。 其中是否存活是我们的标签。很明显,以判断 “ 是否存活 ” 为目的,票号,登船的舱门,乘客编号明显是无关特征, 可以直接删除。姓名,舱位等级,船舱编号,也基本可以判断是相关性比较低的特征。性别,年龄,船上的亲人数 量,这些应该是相关性比较高的特征。 所以,特征工程的第一步是:理解业务。 当然了,在真正的数据应用领域,比如金融,医疗,电商,我们的数据不可能像泰坦尼克号数据的特征这样少,这 样明显,那如果遇见极端情况,我们无法依赖对业务的理解来选择特征,该怎么办呢?我们有四种方法可以用来选 择特征:过滤法,嵌入法,包装法,和降维算法。 当特征的数量多的夸张时,有好几千,此时我们就不能手动的利用pandas来删除特征。需要使用上述介绍的模块 3.1 Filter过滤法 过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法。它是根据各种统计检验中的分数以及相关 性的各项指标来选择特征。 3.1.1 方差过滤 这是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。所以无 论接下来的特征工程要做什么,都要优先消除方差为 0 的特征 。 VarianceThreshold 有重要参数 threshold ,表示方差的阈值,表示舍弃所有方差小于threshold 的特征,不填默认为 0 ,即删除所有的记录都相同的特征。
from sklearn.feature_selection import VarianceThreshold selector=VarianceThreshold()实例化 x_var0=selector.fit_transform(X)#删除不合格特征之后的新特征矩阵可以看见,我们已经删除了方差为 0 的特征,但是依然剩下了 708 多个特征,明显还需要进一步的特征选择。然 而,如果我们知道我们需要多少个特征,方差也可以帮助我们将特征选择一步到位。比如说,我们希望留下一半的 特征,那可以设定一个让特征总数减半的方差阈值,只要找到特征方差的中位数,再将这个中位数作为参数 threshold的值输入就好了
import numpy as np X_fsvar=VarianceThreshold(np.median(X.mean().values)).fit_transform(X)
#当特征是二分类时,特征的取值就是伯努利随机变量,这些变量的方差可以计算为:
var[x]=p(1-p)
#其中X是特征矩阵,p是二分类特征中的一类在这个特征中所占的概率
#若特征是伯努利随机变量,假设p=0.8,即二分类特征中某种分类占到80%以上的时候删除特征 X_bvar=VarianceThreshold(.8*(1-.8)).fit_transform(X)#删除某一特征里有一特征占到80%以上的特征
#knn算法解释:a,b为样本x1,x2为特征 a(x1,x2) b(x11,x22) knn就是计算其特征的欧式距离:sqrt((x1-x11)^2+(x2-x22)^2) 由于knn需要计算每个样本点的距离,所以当样本过大时,运行的时间非常长
#knn vs 随机森林在不同方差过滤效果下的对比 from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.neighbors import KNeighborsClassifier as KNN from sklearn.model_selection import cross_val_score import numpy as np X=data.iloc[:,1:] y=data.iloc[:,0] X_fsvar=VarianceThreshold(np.median(X.var().values)).fit_transform(X) cross_val_score(KNN(),X,y,cv=5).mean()#单次运行会花费30min cross_val_score(KNN(),X_fsvar,y,cv=5).mean()#传入方差过滤后的样本运行时间是20min score=0.9659 %%timeit#会显示这个cell中代码运行的时间,(会运行7次再求平均值) 随机森林 方差过滤前: cross_val_score(RFC(n_estimators=10,random_state=0),X,y,cv=5).mean() score=0.9366 time=11.5s 过滤后: cross_val_score(RFC(n_estimators=10,random_state=0),X_fsvar,y,cv=5).mean() score=0.9388 time=11.2s首先可以观察到的是,随机森林的准确率略逊于 KNN ,但运行时间却连 KNN 的 1% 都不到,只需要十几秒钟。其 次,方差过滤后,随机森林的准确率也微弱上升,但运行时间却几乎是没什么变化,依然是 11 秒钟。 为什么随机森林运行如此之快?为什么方差过滤对随机森林没很大的有影响? 这是由于两种算法的原理中涉及到的 计算量不同。最近邻算法 KNN ,单棵决策树,支持向量机 SVM ,神经网络,回归算法,都需要遍历特征或升维来进 行运算,所以他们本身的运算量就很大,需要的时间就很长,因此方差过滤这样的特征选择对他们来说就尤为重 要。但对于不需要遍历特征的算法,比如随机森林,它随机选取特征进行分枝,本身运算就非常快速,因此特征选 择对它来说效果平平。这其实很容易理解,无论过滤法如何降低特征的数量,随机森林也只会选取固定数量的特征 来建模;而最近邻算法就不同了,特征越少,距离计算的维度就越少,模型明显会随着特征的减少变得轻量。因 此,过滤法的 主要对象 是: 需要遍历特征或升维的算法们 ,而过滤法的 主要目的 是: 在维持算法表现的前提下,帮 助算法们降低计算成本 。 cross_val_score ( RFC ( n_estimators = 10 , random_state = 0 ), X_fsvar , y , cv = 5 ). mean () 菜菜的 sklearn 课堂直播间: https://live.bilibili.com/12582510 sklearn 专题第三期:数据预处理和特征工程 T 首先可以观察到的是,随机森林的准确率略逊于 KNN ,但运行时间却连 KNN 的 1% 都不到,只需要十几秒钟。其 次,方差过滤后,随机森林的准确率也微弱上升,但运行时间却几乎是没什么变化,依然是 11 秒钟。 为什么随机森林运行如此之快?为什么方差过滤对随机森林没很大的有影响? 这是由于两种算法的原理中涉及到的计算量不同。最近邻算法KNN ,单棵决策树,支持向量机 SVM ,神经网络,回归算法,都需要遍历特征或升维来进行运算,所以他们本身的运算量就很大,需要的时间就很长,因此方差过滤这样的特征选择对他们来说就尤为重要。但对于不需要遍历特征的算法,比如随机森林,它随机选取特征进行分枝,本身运算就非常快速,因此特征选 择对它来说效果平平。这其实很容易理解,无论过滤法如何降低特征的数量,随机森林也只会选取固定数量的特征来建模;而最近邻算法就不同了,特征越少,距离计算的维度就越少,模型明显会随着特征的减少变得轻量。因此,过滤法的主要对象是: 需要遍历特征或升维的算法们 ,而过滤法的 主要目的 是: 在维持算法表现的前提下,帮 助算法们降低计算成本 。 3.1.2 相关性过滤 方差挑选完毕之后,我们就要考虑下一个问题:相关性了。我们希望选出与标签相关且有意义的特征,因为这样的特征能够为我们提供大量信息。如果特征与标签无关,那只会白白浪费我们的计算内存,可能还会给模型带来噪音。在sklearn 当中,我们有三种常用的方法来评判特征与标签之间的相关性:卡方, F 检验,互信息。 3.1.2.1 卡方过滤 卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类 feature_selection.chi2 计算每个非负特征和标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名。再结合feature_selection.SelectKBest 这个可以输入 ” 评分标准 “ 来选出前 K 个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。 另外,如果卡方检验检测到某个特征中所有的值都相同,会提示我们使用方差先进行方差过滤。并且,刚才我们已经验证过,当我们使用方差过滤筛选掉一半的特征后,模型的表现时提升的。因此在这里,我们使用threshold= 中位数时完成的方差过滤的数据来做卡方检验(如果方差过滤后模型的表现反而降低了,那我们就不会使用方差过滤后的数据,而是使用原数据):
from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 x_fschi=SelectKBest(chi2,k=300).fit_transform(X_fsvar,y)卡方检验的本质是推测两组数据之间的差异,其检验的原假设是 ” 两组数据是相互独立的 ” 。卡方检验返回卡方值和 P值两个统计量,其中卡方值很难界定有效的范围,而 p 值,我们一般使用 0.01 或 0.05 作为显著性水平,即 p 值判断的边界,具体我们可以这样来看 从特征工程的角度,我们希望选取卡方值很大, p 值小于 0.05 的特征,即和标签是相关联的特征。而调用 SelectKBest 之前,我们可以直接从 chi2 实例化后的模型中获得各个特征所对应的卡方值和 P 值。
chivalue,pvalues=chi2(X_fsvar,y) #k取多少?我们想要消除所有p值大于设定值,比如0.05或0.01的特征: k = chivalue.shape[0] - (pvalues_chi > 0.05).sum() #X_fschi = SelectKBest(chi2, k=填写具体的k).fit_transform(X_fsvar, y) #cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()3.1.2.3 F检验 F 检验,又称 ANOVA,方差齐性检验,是用来捕捉每个特征与标签之间的线性关系的过滤方法。它即可以做回归也 可以做分类,因此包含feature_selection.f_classif (F检验分类)和 feature_selection.f_regression ( F 检验回 归)两个类。其中 F 检验分类用于标签是离散型变量的数据,而 F 检验回归用于标签是连续型变量的数据。 和卡方检验一样,这两个类需要和类 SelectKBest 连用,并且我们也可以直接通过输出的统计量来判断我们到底要设置一个什么样的K 。需要注意的是, F 检验在数据服从正态分布时效果会非常稳定,因此如果使用 F 检验过滤,我们会先将数据转换成服从正态分布的方式 F 检验的本质是寻找两组数据之间的线性关系,其原假设是 ” 数据不存在显著的线性关系 “ 。它返回 F 值和 p 值两个统计量。和卡方过滤一样,我们希望选取 p 值小于 0.05 或 0.01 的特征,这些特征与标签时显著线性相关的 ,而 p 值大于0.05或 0.01 的特征则被我们认为是和标签没有显著线性关系的特征,应该被删除。以 F 检验的分类为例,我们继续在数字数据集上来进行特征选择
from sklearn.feature_selection import f_classif F, pvalues_f = f_classif(X_fsvar,y) k = F.shape[0] - (pvalues_f > 0.05).sum() #X_fsF = SelectKBest(f_classif, k=填写具体的k).fit_transform(X_fsvar, y) #cross_val_score(RFC(n_estimators=10,random_state=0),X_fsF,y,cv=5).mean()3.1.2.4 互信息法 互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。和 F 检验相似,它既可以做回归也可以做分类,并且包含两个feature_selection.mutual_info_classif (互信息分类)和 feature_selection.mutual_info_regression (互信息回归)。这两个类的用法和参数都和 F 检验一模一样,不过互信息法比F 检验更加强大, F 检验只能够找出线性关系,而互信息法可以找出任意关系。 互信息法不返回 p 值或 F 值类似的统计量,它返回 “ 每个特征与目标之间的互信息量的估计 ” ,这个估计量在 [0,1] 之间取值,为0 则表示两个变量独立,为 1 则表示两个变量完全相关。
from sklearn.feature_selection import mutual_info_classif as MIC result = MIC(X_fsvar,y) k = result.shape[0] - sum(result <= 0) #X_fsmic = SelectKBest(MIC, k=填写具体的k).fit_transform(X_fsvar, y) #cross_val_score(RFC(n_estimators=10,random_state=0),X_fsmic,y,cv=5).mean()所有特征的互信息量估计都大于 0 ,因此所有特征都与标签相关。 当然了,无论是 F 检验还是互信息法,大家也都可以使用学习曲线,只是使用统计量的方法会更加高效。当统计量判断已经没有特征可以删除时,无论用学习曲线如何跑,删除特征都只会降低模型的表现。当然了,如果数据量太庞大,模型太复杂,我们还是可以牺牲模型表现来提升模型速度,一切都看大家的具体需求。 3.2 Embedded嵌入法
from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import RandomForestClassifier as RFC RFC_ = RFC(n_estimators =10,random_state=0) X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y) #在这里我只想取出来有限的特征。0.005这个阈值对于有780个特征的数据来说,是非常高的阈值,因为平均每个特征 只能够分到大约0.001的feature_importances_ X_embedded.shape #模型的维度明显被降低了 #同样的,我们也可以画学习曲线来找最佳阈值对于有 feature_importances_ 的模型来说,若重要性低于提供的阈值参数,则认为这些特征不重要并被移除。 feature_importances_的取值范围是 [0,1] ,如果设置阈值很小,比如 0.001 ,就可以删除那些对标签预测完全没贡献的特征。如果设置得很接近1 ,可能只有一两个特征能够被留下 3.3 Wrapper包装法 包装法也是一个特征选择和算法训练同时进行的方法,与嵌入法十分相似,它也是依赖于算法自身的选择,比如 coef_属性或 feature_importances_ 属性来完成特征选择。但不同的是,我们往往使用一个目标函数作为黑盒来帮助我们选取特征,而不是自己输入某个评估指标或统计量的阈值。包装法在初始特征集上训练评估器,并且通过 coef_属性或通过 feature_importances_ 属性获得每个特征的重要性。然后,从当前的一组特征中修剪最不重要的特征。在修剪的集合上递归地重复该过程,直到最终到达所需数量的要选择的特征。区别于过滤法和嵌入法的一次训练解决所有问题,包装法要使用特征子集进行多次训练,因此它所需要的计算成本是最高的。 注意,在这个图中的 “ 算法 ” ,指的不是我们最终用来导入数据的分类或回归算法(即不是随机森林),而是专业的数据挖掘算法,即我们的目标函数。这些数据挖掘算法的核心功能就是选取最佳特征子集 最典型的目标函数是递归特征消除法( Recursive feature elimination, 简写为 RFE )。它是一种贪婪的优化算法, 旨在找到性能最佳的特征子集。 它反复创建模型,并在每次迭代时保留最佳特征或剔除最差特征,下一次迭代时, 它会使用上一次建模中没有被选中的特征来构建下一个模型,直到所有特征都耗尽为止。 然后,它根据自己保留或 剔除特征的顺序来对特征进行排名,最终选出一个最佳子集。包装法的效果是所有特征选择方法中最利于提升模型 表现的,它可以使用很少的特征达到很优秀的效果。除此之外,在特征数目相同时,包装法和嵌入法的效果能够匹 敌,不过它比嵌入法算得更见缓慢,所以也不适用于太大型的数据。相比之下,包装法是最能保证模型效果的特征选择方法。 feature_selection.RFE 参数 estimator 是需要填写的实例化后的评估器, n_features_to_select 是想要选择的特征个数, step 表示每次迭 代中希望移除的特征个数。除此之外,RFE 类有两个很重要的属性, .support_ :返回所有的特征的是否最后被选 中的布尔矩阵,以及.ranking_ 返回特征的按数次迭代中综合重要性的排名。类 feature_selection.RFECV 会在交叉 验证循环中执行RFE 以找到最佳数量的特征,增加参数 cv ,其他用法都和 RFE一模一样。
from sklearn.feature_selection import RFE RFC_ = RFC(n_estimators =10,random_state=0) selector = RFE(RFC_, n_features_to_select=340, step=50).fit(X, y) selector.support_.sum() selector.ranking_ X_wrapper = selector.transform(X) cross_val_score(RFC_,X_wrapper,y,cv=5).mean()



