sklearn数据预处理和特征工程

文章目录

    • 1 数据挖掘的五大流程
    • 2 sklearn中数据处理和特征工程的模块
    • 3 数据预测处理Preprocessing和Impute
      • 3.1 数据无量纲化
      • 3.2 缺失值
      • 3.3 处理分类型特征
      • 3.4 处理连续型特征:二值化和分箱
    • 4 特征选择 feature_selection
      • 4.1 Filter过滤法
        • 4.1.1方差过滤
        • 4.1.2 相关性过滤
        • 4.1.3 过滤法总结
      • 4.2 Embedded嵌入法
      • 4.3 Wrapper包装法
      • 4.4 特征选择总结

1 数据挖掘的五大流程

1. 获取数据

2. 数据预处理
数据预处理是从数据中检测,纠正或删除损坏,不准确或不适用于模型的记录的过程
可能面对的问题有:数据类型不同,比如有的是文字,有的是数字,有的含时间序列,有的连续,有的间断。
也可能,数据的质量不行,有噪声,有异常,有缺失,数据出错,量纲不一,有重复,数据是偏态,数据量太
大或太小
数据预处理的目的:让数据适应模型,匹配模型的需求

3. 特征工程:
特征工程是将原始数据转换为更能代表预测模型的潜在问题的特征的过程,可以通过挑选最相关的特征,提取
特征以及创造特征来实现。其中创造特征又经常以降维算法的方式实现。
可能面对的问题有:特征之间有相关性,特征和标签无关,特征太多或太小,或者干脆就无法表现出应有的数
据现象或无法展示数据的真实面貌
特征工程的目的:1) 降低计算成本,2) 提升模型上限

4. 建模,测试模型并预测出结果

5. 上线,验证模型效果

2 sklearn中数据处理和特征工程的模块

  • preprocessing: 包含数据预处理的所有内容
  • Impute:填补缺失值专用
  • feature_selection:包含特征选择的各种方法实践
  • decomposition:包含降维算法

3 数据预测处理Preprocessing和Impute

3.1 数据无量纲化

什么是?

  • 将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布
    的需求,这种需求统称为将数据“无量纲化”

好处

  • 在梯度和矩阵为核心的算法中,如逻辑回归、svm、bp,无量纲化可以加快求解速度
  • 在距离模型中,如k-means,k-近邻,可以帮助提升模型精度,避免某一个取值范围特别大的特征对距离计算造成的影响。
  • 特例:决策树和树的集成算法们,不用进行无量钢化。

数据的无量纲化可以是线性的,也可以是非线性的。线性的包括中心化(Zero-centered或Mean-subtraction)和缩放处理(Scale)中心化的本质是让所有的值减去一个固定值,即让数据样本平移到某个位置。缩放的本质是除以某个值,将数据固定在某个范围之中,取对数也算是一种缩放。

preprocess.MinMaxScaler

  • 公式如下

x ∗ = x − m i n ( x ) m a x ( x ) − m i n ( x ) x^* = \frac{x-min(x)}{max(x)-min(x)} x=max(x)min(x)xmin(x)

  • 代码
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]

pd.DataFrame(data)
#实现归一化
scaler = MinMaxScaler() #实例化
scaler = scaler.fit(data) #fit,在这里本质是生成min(x)和max(x)
result = scaler.transform(data) #通过接口导出结果
print result
result_ = scaler.fit_transform(data) #训练和导出结果一步达成
scaler.inverse_transform(result) #将归一化后的结果逆转

#使用MinMaxScaler的参数feature_range实现将数据归一化到[0,1]以外的范围中
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler(feature_range=[5,10]) #依然实例化
result = scaler.fit_transform(data) #fit_transform一步导出结果

#当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_nor
#逆转归一化
X_returned = X_nor * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0)
X_returned

preprocessing.StandardScaler
数据按照均值中心化后,再按照标准差缩放,数据将服从均值为0,方差为1的正太分布。称之为数据标准化(又称Z-score normalization),公式如下:
x ∗ = x − μ σ x^* = \frac{x-\mu}{\sigma} x=σxμ

  • 代码
from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = StandardScaler() #实例化
scaler.fit(data) #fit,本质是生成均值和方差
scaler.mean_ #查看均值的属性mean_
scaler.var_ #查看方差的属性var_
x_std = scaler.transform(data) #通过接口导出结果
x_std.mean() #导出的结果是一个数组,用mean()查看均值
x_std.std() #用std()查看方差
scaler.fit_transform(data) #使用fit_transform(data)一步达成结果
scaler.inverse_transform(x_std) #使用inverse_transform逆转标准化

对于StandardScaler和MinMaxScaler来说,空值NaN会别当成缺失值,在fit的时候忽略,在transform的时候保持NaN的状态显示。
另外,fit时只允许至少导入二维数组,一维数组会报错

StandardScaler和MinMaxScaler如何选择
大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。

MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。

建议先试试看StandardScaler,效果不好再试试看MinMaxScaler。

sklearn中还提供了其他的缩放处理。例如,在希望压缩数据,却不影响数据的稀疏性时(不影响矩阵中取值为0的个数时),可以使用MaxAbsScaler。在异常值多,噪声非常大时,选择分位数来无量纲化,使用RobustScaler。详细参考下表:

sklearn数据预处理和特征工程_第1张图片

3.2 缺失值

加载数据

import pandas as pd
data = pd.read_csv("../data/Narrativedata.csv",index_col=0)
data.head()

缺失值处理

data.info()
#填补年龄
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn当中特征矩阵必须是二维
Age[:20]
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer() #实例化,默认均值填补
imp_median = SimpleImputer(strategy="median") #用中位数填补
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填补
imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成调取结果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)
imp_mean[:20]
imp_median[:20]
imp_0[:20]

#在这里我们使用中位数填补Age
data.loc[:,"Age"] = imp_median
data.info()

#使用众数填补Embarked
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1)
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
data.info() # 直接可以看出每列的空值情况

3.3 处理分类型特征

preprocessing.LabelEncoder:标签专用,能够将分类转换为分类数值

from sklearn.preprocessing import LabelEncoder
y = data.iloc[:,-1] #要输入的是标签,不是特征矩阵,所以允许一维
le = LabelEncoder() #实例化
le = le.fit(y) 		#导入数据
label = le.transform(y) #transform接口调取结果
print le.classes_ 	#属性.classes_查看标签中究竟有多少类别
print label 			#查看获取的结果label

le.fit_transform(y) #也可以直接fit_transform一步到位
le.inverse_transform(label) #使用inverse_transform可以逆转

data.iloc[:,-1] = label #让标签等于我们运行出来的结果
data.head()

#可以直接转化
from sklearn.preprocessing import LabelEncoder
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])

preprocessing.OrdinalEncoder: 特征专用,能够将分类特征转换为分类数值, 输入不能有NaN

from sklearn.preprocessing import OrdinalEncoder
#接口categories_对应LabelEncoder的接口classes_,一模一样的功能
data_ = data.copy()
print data_.head()
print OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
print data_.head()  # 全部转成数字编码

preprocessing.OneHotEncoder:独热编码,创建哑变量

三种不同性质的分类数据
1) 舱门(S,C,Q)
三种取值S,C,Q是相互独立的,彼此之间完全没有联系,表达的是S≠C≠Q的概念。这是名义变量。
2) 学历(小学,初中,高中)
三种取值不是完全独立的,我们可以明显看出,在性质上可以有高中>初中>小学这样的联系,学历有高低,但是学历取值之间却不是可以计算的,我们不能说小学 + 某个取值 = 初中。这是有序变量。
3) 体重(>45kg,>90kg,>135kg)
各个取值之间有联系,且是可以互相计算的,比如120kg - 45kg = 90kg,分类之间可以通过数学计算互相转换。这是有距变量。

from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]
enc = OneHotEncoder(categories='auto').fit(X) # auto 在0.19版本中是不支持的
result = enc.transform(X).toarray() # 如果不to_array则是稀疏矩阵
print result 

#依然可以直接一步到位,
OneHotEncoder(categories='auto').fit_transform(X).toarray()

#依然可以还原
pd.DataFrame(enc.inverse_transform(result))


enc.get_feature_names() # 稀疏矩阵中列的名字

#axis=1,表示跨行进行合并,axis=1是将两表左右相连,如果是axis=0,就是将量表上下相连
newdata = pd.concat([data,pd.DataFrame(result)],axis=1)
print newdata.head()

# 丢失没用的列
newdata.drop(["Sex","Embarked"],axis=1,inplace=True)
newdata.columns =
["Age","Survived","Female","Male","Embarked_C","Embarked_Q","Embarked_S"]
print newdata.head()

小结
sklearn数据预处理和特征工程_第2张图片
数据类型及常用的统计量
sklearn数据预处理和特征工程_第3张图片

3.4 处理连续型特征:二值化和分箱

sklearn.preprocessing.Binarizer
根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)。

#将年龄二值化
data_2 = data.copy()
from sklearn.preprocessing import Binarizer
X = data_2.iloc[:,0].values.reshape(-1,1) # 类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X) # 阈值
print transformer  # 得到0 和 1的数组
data_2.iloc[:,0] = transformer

preprocessing.KBinsDiscretizer
分类变量的类,能够将连续型变量排序后按顺序分箱后编码
sklearn数据预处理和特征工程_第4张图片

from sklearn.preprocessing import KBinsDiscretizer
X = data.iloc[:,0].values.reshape(-1,1)
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est.fit_transform(X)

#查看转换后分的箱:变成了一列中的三箱
set(est.fit_transform(X).ravel())
est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')

#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray()

4 特征选择 feature_selection

特征提取(feature extraction)
从文字,图像,声音等其他非结构化数据中提取新信息作为特征。比如说,从淘宝宝贝的名称中提取出产品类别,产品颜色,是否是网红产品等等
特征创造(feature creation)
把现有特征进行组合,或互相计算,得到新的特征。比如说,我们有一列特征是速度,一列特征是距离,我们就可以通过让两列相处,创造新的特征:通过距离所花的时间
特征选择(feature selection)
从所有的特征中,选择出有意义,对模型有帮助的特征,以避免必须将所有特征都导入模型
去训练的情况

四种方法可以用来选择特征:过滤法,嵌入法,包装法,和降维算法

导入数据

import pandas as pd
data = pd.read_csv(r"digitrecognizor.csv")
X = data.iloc[:,1:]
y = data.iloc[:,0]
X.shape

4.1 Filter过滤法

过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法。它是根据各种统计检验中的分数以及相关性的各项指标来选择特征。

4.1.1方差过滤

VariancThreshold
某个特征如果方差很小,说明该特征的值都是差不多的,则该特征对样本区分没有什么作用。所以要优先消除方差为0的特征。

from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold() 		#实例化,不填参数默认方差为0
X_var0 = selector.fit_transform(X) #获取删除不合格特征之后的新特征矩阵
#也可以直接写成 X = VairanceThreshold().fit_transform(X)
print X_var0.shape  # 打印去除方差为0后的数据维度
# 设置方差的中位数为阈值
import numpy as np
x_fsvar = VarianceThreshold(np.median(x.var().values)).fit_transform(x)

当特征是二分类时,特征的取值就是伯努利随机变量,这些变量的方差可以计算为:
V a r [ X ] = p ( 1 − p ) Var[X] = p(1-p) Var[X]=p(1p)
其中X是特征矩阵,p是二分类特征中的一类在这个特征中所占的概率。

#若特征是伯努利随机变量,假设p=0.8,即二分类中某类分类占到80%以上的时候删除特征。
x_bar = VarianceThreshold(.8 * (1 - .8)).fit_transform(X)

为什么随机森林运行如此之快为什么方差过滤对随机森林没很大的有影响
这是由于两种算法的原理中涉及到的计算量不同。最近邻算法KNN,单棵决策树,支持向量机SVM,神经网络,回归算法,都需要遍历特征或升维来进行运算,所以他们本身的运算量就很大,需要的时间就很长,因此方差过滤这样的特征选择对他们来说就尤为重要。
但对于不需要遍历特征的算法,比如随机森林,它随机选取特征进行分枝,本身运算就非常快速,因此特征选择对它来说效果平平。这其实很容易理解,无论过滤法如何降低特征的数量,随机森林也只会选取固定数量的特征来建模;而最近邻算法就不同了,特征越少,距离计算的维度就越少,模型明显会随着特征的减少变得轻量。因此,过滤法的主要对象是:需要遍历特征或升维的算法们,而过滤法的主要目是:在维持算法表现的前提下,帮助算法们降低计算成本

方差过滤的影响总结

阈值很小,被过滤掉的特征比较少 阈值较大
模型表现 影响不大 可能会变好,代表过滤掉的都是噪音,也可能变糟糕,代表被过滤掉的很多都是有效特征
运行时间 可能较低模型的运行时间 一定时间上能降低模型的运行时间,算法下遍历特征时的计算特征越复杂,运行时间下降的越多

选择超参数threshold
一般会先使用阈值为0,或者阈值很小的方差过滤。然后选用更优秀的特征选择方法继续消减特征数量。

4.1.2 相关性过滤

卡方过滤是专门针对离散型标签,即分类问题
卡方检验类feature_selection.chi2计算每个非负特征和标签之间的卡方统计量,并且依照卡方统计量由高到低为特征排名。再结合feature_selection.SelectKBest选出前K个分数最高的特征类。借此可以去除最可能独立于标签,与我们分类目的无关的特征。

如果卡方检验检测到某个特征中中的特征值都相同,则是提示我们需要先进行方差过滤。
如果先使用了方差过滤,模型效果好了,则进行卡方检测时就用方差过滤以后的数据,反之则直接用原始数据。

# 导包
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

#假设在这里我一直我需要300个特征
X_fschi = SelectKBest(chi2, k=300).fit_transform(X_fsvar, y)
X_fschi.shape
cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()

验证一下模型的效果如何

cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()

选择超参数K

方法一:画学习曲线。直观但是速度很慢

#======【TIME WARNING: 5 mins】======#
%matplotlib inline
import matplotlib.pyplot as plt
score = []
for i in range(390,200,-10):
X_fschi = SelectKBest(chi2, k=i).fit_transform(X_fsvar, y)
once = cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
score.append(once)
plt.plot(range(350,200,-10),score)
plt.show()

方法二:看p值选择k
卡方检验返回卡方值和P值两个统计变量,其中卡方值很难界定有效的范围,但是P值,一般使用0.01或者0.05作为显著性水平。即p值判断的边界。

p值 <=0.05或0.01 >0.05或0.01
数据差异 差异不是自然形成的 这些差异是很自然的样本误差
相关性 两组数据是相关的 两组数据是独立的
原假设 拒绝原假设,接受备选假设 接受原假设

从特征工程的角度,一般希望选取卡方值很大,p值小于0.05的特征,即和标签是相关联的在调用SelectKBest之前,可以直接从chi2实例化后的模型中获得各个特征所对应的卡方值和P值。

chivalue, pvalues_chi = 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()

可以观察到,所有的特征的p值都是0,说明对于digit recognizor数据集来说,方差验证已经把所有和标签无关的特征都剔除掉了。因此,舍弃任何一个特征都会使模型效果下降。

F检验
F检验又称ANOVA,方差齐性检验,可以捕捉,每个特征与标签之间的线性关系的过滤方法。可用于回归又可以用户分类。因此,包含feature_section.f_classif(用于标签是离散型)和feature_selection.f_regression(用于标签是连续性)两个类。

类似于卡方检验,这两个类都需要结合SelectKBest使用。因此也需要设定K的值。F检验在数据服从正态分布时效果非常稳定,因此一般会先将数据转换成正太分布,再使用F检验过滤。

F检验的本质是寻找两组数据之间的线性关系,其原假设是“数据不存在显著的线性关系”。它返回F值和p值两个统计量。和卡方过滤一样,选取p值小于0.05或者0.01的特征,这些特征与标签是显著线性相关的。,反之则该特征应该被删除。

from sklearn.feature_selection import f_classif
F, pvalues_f = f_classif(X_fsvar,y)
print F
print pvalues_f
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() 

互信息法
互信息发用来捕捉每个特征与标签之间的任意关系(线性和非线性)的过滤方法。也是可以做回归和分类。包含feature_selection.mutual_info_classif和feature_selection.mutual_info_regression。

互信息法不返回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,因此所有特征都与标签相关。

4.1.3 过滤法总结

通常来说,会先使用方差过滤,然后使用互信息法来捕捉相关性,不过各式各样的过滤方式也是要考虑的。各类方法的总结如下:

说明 超参数选择
VarianceThreshold 方差过滤,可输入方差的阈值,返回方差大于阈值的新特征矩阵 一般选择0或1来筛选,也可以画一学习曲线或中位数模型来帮助确认
SelectKBest 用来选取K个统计量结果最佳的特征,生成符合统计量要求的新特征矩阵 看配合使用的统计量
chi2 卡方检验,专用于分类算法,捕捉相关性 追求p小于显著性水平的特征
f_classif / f_regression F检验,要求数据服从正太分布 追求p小于显著水平的特征
mutual_info_classif / mutual_info_regression 互信息检测,不能用于稀疏矩阵 追求互信息估计大于0特征

4.2 Embedded嵌入法

嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同是进行。例如决策树和树的集成模型中的feature_importances_属性。
sklearn数据预处理和特征工程_第5张图片
嵌入法的缺点
相当于过滤法,嵌入法无法找到一个固定的值来衡量哪个特征对模型有作用。相当于权重系数就是一个超参数。
另外,嵌入法和应用的算法的计算速度有关,如果采用计算量很大的算法,嵌入法本身也会十分耗时。

feature_selection.SelectFromModel
class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1, max_features=None)

SelectFromModel是一个元变换器,可以与任何拟合后具有coef_,feature_importances_属性或参数中可选惩罚项的评估器一起使用(随机森林和树模型就具有属性feature_importances_,逻辑回归就带有l1和l2惩罚项,svm也支持l2惩罚项)

对于有feature_importances_的模型来说,若重要性低于提供的阈值,则认为这些特征不重要。
对于使用惩罚项的模型嵌入法,正则化惩罚越大,特征在模型中的对于系数就会越小。当正则化惩罚项打到一定程度的时候,部分特征系数就会变0,当正则化惩罚项增大到一定程度时,所有特征系数都会趋于0,此时我们可以观察哪一部分特征更容易变成0,这部分特征可以被筛掉。另外对于SVM和LR使用参数C来控制返回的特征的系数性,参数C越小,返回费特征越少。Lasso回归,用alpha参数来控制返回的特征矩阵,alpha的纸越大,返回的特征越少。

参数说明

参数 说明
estimator 使用的模型评估器,只要带feature_importances_或coef_属性,或者带有l1和l2惩罚项的模型都可以使用
threshold 特征重要性阈值,重要性小于该阈值的会被删除
prefit 默认为False,判断是否将实例化后的模型直接传递给构造函数。如果为True,则必须直接调用fit和transform,不能使用fit_transform,并且SelectFromModel不能与cross_val_score,GridSearchCV一起使用
norm_order k可以在非0整数,正无穷,负无穷,默认为1。在评估器的coef_属性高于1维的情况下,用于过滤低于阈值的系数的向量的范数的阶数
max_features 要选择的最大特征数,要禁用阈值并且根据max_features选择,则设置threshold=-np.inf

一般主要考虑前两个参数。以随机森林为例:

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
 
#模型的维度明显被降低了 #同样的,我们也可以画学习曲线来找最佳阈值
 
#======【TIME WARNING:10 mins】======#
import numpy as np import matplotlib.pyplot as plt
RFC_.fit(X,y).feature_importances_
threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20)
score = [] for i in threshold:    
	X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
	once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
	score.append(once)
	plt.plot(threshold,score) plt.show()

在嵌入法下,我们很容易就能够实现特征选择的目标:减少计算量,提升模型表现。因此,比起要思考很多统计量 的过滤法来说,嵌入法可能是更有效的一种方法。然而,在算法本身很复杂的时候,过滤法的计算远远比嵌入法要 快,所以大型数据中,我们还是会优先考虑过滤法。

4.3 Wrapper包装法

和嵌入法的区别:使用一个目标函数作为黑盒来帮助我们选取特征,而不是自己输入某个评估指标或者统计量的阈值。另外,过滤法和嵌入法是一次训练解决所有问题,包装法要使用特征子集进行多次训练,因此计算成本更高。
sklearn数据预处理和特征工程_第6张图片
最典型的目标函数是递归特征消除法(Recursive feature elimination, 简写为RFE)它是一种贪婪优化算法,旨在找到性能最佳的特征子集。

feature_selection.RFE
class sklearn.feature_selection.RFE (estimator, n_features_to_select=None, step=1, verbose=0)
参数说明

参数 说明
estimator 需要填写实例化后的评估器
n_features_to_select 想要选择的特征个数
step 每次迭代中希望移除的特征个数

重要属性
.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)
print selector.support_.sum()
print selector.ranking_

X_wrapper = selector.transform(X)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()

学习曲线

#======【TIME WARNING: 15 mins】======#
 
score = [] for i in range(1,751,50):   
	X_wrapper = RFE(RFC_,n_features_to_select=i, step=50).fit_transform(X,y)  
	once = cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
	score.append(once) 
plt.figure(figsize=[20,5]) 	
plt.plot(range(1,751,50),score) 
plt.xticks(range(1,751,50)) 
plt.show()

sklearn数据预处理和特征工程_第7张图片
可以看出,在包装法下,应用50个特征时,模型的表现已经达到了90%以上,比嵌入法和过滤法都高效。

4.4 特征选择总结

经验来说,过滤法更快速,但更粗糙。包装法和嵌入法更精确,比较适合具体到算 法去调整,但计算量比较大,运行时间长。
当数据量很大的时候,优先使用方差过滤和互信息法调整,再上其他特 征选择方法。使用逻辑回归时,优先使用嵌入法。使用支持向量机时,优先使用包装法。迷茫的时候,从过滤法走起,看具体数据具体分析.

你可能感兴趣的:(sklearn机器学习)