数据预处理与特征工程

1.数据预处理

概念:数据预处理是从数据中检测,纠正或删除损坏,不准确或不适用模型的记录的过程

可能面对的问题:

  • 数据类型不同:比如有的是文字,有的是数字,有的含时间序列,有的连续,有的离散
  • 数据的质量不行:有噪声,有异常,有缺失,数据出错,量纲不一,有重复,数据是偏态,数据量太大或太小

数据预处理的目的:让数据使用模型,匹配模型的需求

1.1 数据无量纲化

数据的无量纲化是指将不同规格的数据转换到统一规格,或者讲不通分布的数据转换到某个特定分布的需求,这种需求统称为数据的无量纲化

1.1.1 数据归一化preprocessing.MinMaxScaler

将数据压缩到指定的范围,默认为[0,1],也可以通过参数feature_range把数据压缩到其他范围
x^*=\frac{x-min(x)}{max(x)-min(x)}

from sklearn.preprocessing import MinMaxScaler
data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = MinMaxScaler().fit(data)  # fit本质是生成最大值和最小值
result = scaler.transform(data)
result
#MinMaxScaler().fit_transform(data)  也可以一步到位
array([[0.  , 0.  ],
       [0.25, 0.25],
       [0.5 , 0.5 ],
       [1.  , 1.  ]])

通过方法inverse_transform,可以将归一化之后的结果逆转

result_ = inverse_transform(result)
array([[-1. ,  2. ],
       [-0.5,  6. ],
       [ 0. , 10. ],
       [ 1. , 18. ]])

通过参数feature_range把数据压缩到其他范围

data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = MinMaxScaler(feature_range=[5,10])  # 通过参数feature_range把数据压缩到[5,10]
result = scaler.fit_transform(data)
result
array([[ 5.  ,  5.  ],
       [ 6.25,  6.25],
       [ 7.5 ,  7.5 ],
       [10.  , 10.  ]])
1.1.2 数据标准化preprocessing.StandardScaler

x^*=\frac{x-\mu}{\sigma}
通过标准化处理,将数据为标准正态分布

from sklearn.preprocessing import StandardScaler
data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = StandardScaler()
scaler = scaler.fit(data)  #fit,本质是生成均值和方差
scaler.mean_  # 返回各列的平均值 array([-0.125,  9.   ])
scaler.var_  # 返回各列的方差 array([ 0.546875, 35.      ])
result = scaler.transform(data)
result
array([[-1.18321596, -1.18321596],
       [-0.50709255, -0.50709255],
       [ 0.16903085,  0.16903085],
       [ 1.52127766,  1.52127766]])

查看标准化之后的平均值和方差,看是否符合标准正态分布

result.mean()  # 返回值1.0
result.var()  # 返回值0.0
preprocessing.MinMaxScalerpreprocessing.StandardScaler的选择问题

因为preprocessing.MinMaxScaler对异常值非常敏感,所以在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择

MinMaxScaler在不涉及距离度量,梯度,方差,协方差计算以及数据需要被压缩到特定区间时使用广泛。

综上,可以优先选择StandardScaler当效果不好时可以考虑选择MinMaxScaler

1.2 缺失值处理

运用impute.SimpleImpute(missing_values=np.nan,strategy=,fill_value=,copy)模块对缺失值进行填充处理

参数 含义
missing_values 告诉Simpleimpute缺失值的类型
startegy 用于填补缺失值的策略,mean,median,most_frequent,constant
fill_value 当参数strategy=constant,可输入字符串或数字,表示要填充的值
copy 默认为True,将创建特征矩阵的副本,反之则会将缺失值填补到原本的特征矩阵中去

(1)读取修改之后的带有缺失数据的泰坦尼克号数据集

import pandas as pd
df = pd.read_csv('Narrativedata.csv',index_col=0)
df.head()
Age Sex Embarked Survived
0 22.0 male S No
1 38.0 female C Yes
2 26.0 female S Yes
3 35.0 female S Yes
4 35.0 male S No

(2) 查看数据集的情况

df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age         714 non-null float64
Sex         891 non-null object
Embarked    889 non-null object
Survived    891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB

(3)对Age分别用平均值,0,中位数进行缺失值填充

Age = df.loc[:,'Age'].values.reshape(-1,1)  # sklearn当中,特征矩阵必须是二维数组
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer(missing_values=np.nan,strategy='mean').fit_transform(Age)
imp_median = SimpleImputer(missing_values=np.nan,strategy='median').fit_transform(Age)
imp_0 = SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(Age)
imp_mean[:20]
array([[22.        ],
       [38.        ],
       [26.        ],
       [35.        ],
       [35.        ],
       [29.69911765],
       [54.        ],
       [ 2.        ],
       [27.        ],
       [14.        ],
       [ 4.        ],
       [58.        ],
       [20.        ],
       [39.        ],
       [14.        ],
       [55.        ],
       [ 2.        ],
       [29.69911765],
       [31.        ],
       [29.69911765]])
# 在这里我们使用中位数对Age进行填补,因为mean有小数,年龄是没有小数的
df.loc[:,'Age'] = imp_median
df.info()  # 再次查看数据集,可以发现Age已经全部被填充完毕了
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age         891 non-null float64
Sex         891 non-null object
Embarked    889 non-null object
Survived    891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB

同理使用同样的方法对Embarked进行缺失值填充处理

我们也可以直接使用pandas对缺失数据进行填充

import pandas as pd
import numpy as np
data = pd.read_csv('Narrativedata.csv',index_col=0)
data.loc[:,'Age'] = data.loc[:,'Age'].fillna(data.loc[:,'Age'].median())
data.dropna(axis=0,inplace=True)  # axis=0,在列方向上对行进行操作

1.3 处理分类型特征:编码与哑变量

1.3.1 编码

在实际生活中我们所收集到的特征信息,并不是以数字表示的,而是以文字表示的,比如收款方式,支付宝或者微信,学历,高中,大学,硕士,这些文字变量,机器学习是无法fit的,所以在建立模型之前要事先对这些变量进行处理,将文字转化为数字变量,这一过程称之为编码,而这些文字本质上代表类别,所以具有分类型数据的特征

标签编码preprocessing.LabelEncoder
from sklearn.preprocessing import LabelEncoder

y = df.iloc[:,-1]  # 此处fit的是标签,所以可以是一维的
le = LabelEncoder().fit(y)  # 实例化导入数据
label = le.transform(y)  # transform接口调取结果
le.classes_  # 通过classes_属性,查看标签中究竟有多少类别
#[*set(y)]  也可以直接查看标签中的不重复类别
array(['No', 'Unknown', 'Yes'], dtype=object)
df.iloc[:,-1] = label  #使用编码后的标签替换原标签
df.head()
Age Sex Embarked Survived
0 22.0 male S 0
1 38.0 female C 2
2 26.0 female S 2
3 35.0 female S 2
4 35.0 male S 0
特征编码preprocessing.OrdinalEncode
from sklearn.preprocessing import OrdinalEncoder
df_ = df.copy()
# 把Sex和Embarked转化为数值变量
df_.iloc[:,1:3] = OrdinalEncoder().fit_transform(df_.iloc[:,1:3]) 
df_head()
Age Sex Embarked Survived
0 22.0 male 2.0 0
1 38.0 female 0.0 2
2 26.0 female 2.0 2
3 35.0 female 2.0 2
4 35.0 male 2.0 0
独热编码:创建特征哑变量preprocessing.OneHotEncode
  • 名义变量:指变量之间没有完全没有任何联系,相互独立,比如舱门(S,C,Q)
  • 有序变量:变量不是完全独立,存在一定的顺序联系,但是各个取值之间不能进行运算,例如(小学,初中,高中,大学)
  • 有距变量:指分类变量之间可以通过运算来相互转换,例如(体重>45kg,>90kg,>135kg)
    所以在上面特征编码的方式里,是存在错误的,舱门和性别并不具备可运算关系,所以我们要运用独热编码,将其转化为哑变量
from sklearn.preprocessing import OneHotEncoder
X = df.iloc[:,1:3]
enc = OneHotEncoder(categories='auto').fit(X)
result = enc.transform(X).toarray()
result
#OneHotEncoder(categories='auti').fit_transform(X).toarray()    代码一步到位
array([[0., 1., 0., 0., 1.],
       [1., 0., 1., 0., 0.],
       [1., 0., 0., 0., 1.],
       ...,
       [1., 0., 0., 0., 1.],
       [0., 1., 1., 0., 0.],
       [0., 1., 0., 1., 0.]])
enc.get_feature_names()  # 得到每一列的哑变量名称
array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)
result = pd.DataFrame(result)
df.drop(['Sex','Embarked'],axis=1,inplace=True)
newdata = pd.concat([df,result],axis=1,columns=['Age','Survived','female','male','Embarked_C','Embarked_Q','Embarked_S'])
newdata.head()
Age Survived female male Embarked_C Embarked_Q Embarked_S
0 22.0 0 0.0 1.0 0.0 0.0 1.0
1 38.0 2 1.0 0.0 1.0 0.0 0.0
2 26.0 2 1.0 0.0 0.0 0.0 1.0
3 35.0 2 1.0 0.0 0.0 0.0 1.0
4 35.0 0 0.0 1.0 0.0 0.0 1.0

同样的标签也可以做哑变量,使用的模块为preprocessing.LabelBinarizer

1.4处理连续型特征:二值化与分类变量

1.4.1 二值化preprocessing.Binarizer

根据阈值将数值二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0,默认阈值为0是,特征中所有的正值为1,负值为0,二值化是对文本计数数据的常见操作,可以决定仅考虑某种现象的存在与否,还可以用作考虑布尔随机变量的估计器的预处理步骤

# 将年龄二值化
data_2 = newdata.copy()
from sklearn.preprocessing import Binarizer
x = data_2.loc[:,'Age'].values.reshape(-1,1)  # 特征必须是二维的
transformer = Binarizer(threshold=30).fit_transform(x)
transformer
array([[0.],
       [1.],
       [0.],
       [1.],
       [1.],
       [0.],
       [1.],
       [0.],
       [0.],
       ……
1.4.2 分类变量preprocessing.KBinsDiscretizer

这是将连续型变量划分为分类变量的类,能够将连续型变量排序之后按顺序分箱后编码

参数 含义&输入
n_bins 每个特征中分箱的个数,默认为5,一次会被运用到所有导入的特征
encode 编码的方式,默认onehot哑变量,返回稀疏矩阵,ordinal每个特征的每个箱都被编码为一个整数,返回一列是一个特征,每个特征下含有不同整数编码的箱的矩阵
strategy 用来定义箱宽的方式,默认quantile表示等位分箱,uniform表示等宽分箱,kmeans表示聚类分箱
# 将年龄进行分箱
data_3 = newdata.copy()
x = data_3.loc[:,'Age'].values.reshape(-1,1)  # 特征必须是二维的
from sklearn.preprocessing import KBinsDiscretizer
est = KBinsDiscretizer(n_bins=3,encode='ordinal',strategy='quantile')
result = est.fit_transform(x)
set(result.ravel())  # 返回值{0.0, 1.0, 2.0}
# 设置编码方式为独热编码
est = KBinsDiscretizer(n_bins=3,encode='onehot',strategy='uniform')
result = est.fit_transform(x).toarray()
set(result.ravel())  #  返回值{0.0, 1.0}

2.特征选择

特征提取
(feature extraction)
特征创造
(feature creation)
特征选取
(feature selection)
从图像,文字,声音等其他非结构化数据中提取新信息作为特征 把现有特征进行组合,或相互计算得到新的特征 从所有的特征中选出有意义,对模型有帮助的特征,以避免把所有特征都导入模型取训练结果
import pandas as pd
data = pd.read_csv('digit recognizor.csv')
x = data.iloc[:,1:]
y = data.iloc[:,0]
x.shape
(42000, 784)

可见x具有相当多的特征,如果将所有的特征都导入矩阵,无疑会给矩阵的运行增加负担,所以我们要事先对齐进行筛选

2.1 Filter过滤法

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

说明 超参数的选择
VarianceThreshold 方差过滤,可输入方差阈值,返回方差大于阈值的新特征矩阵 一般选取阈值为0过滤掉特征值差异小的特征
SelectKBest 用来选取K个统计量结果最佳的特征,生成符合统计量要求的新特征矩阵 与卡方检验,F检验和互信息法配合使用
chi2 卡方检验,用于分类算法,捕捉相关性 追求p值小于显著性水平的特征
f_classif F检验分类,只能捕捉线性相关,要求数据服从正态分布 追求P值小于显著性水平的特征
f_regression F检验回归,只能捕捉线性相关,要求数据服从正太分布 追求p值小于显著性水平的特征
mutual_info_classif 互信息分类,可以捕捉任何相关性,不能用于稀疏矩阵 追求互信息估计大于0的特征
mutual_info_regression 互信息分类,可以捕捉任何相关性,不能用于稀疏矩阵 追求互信息估计大于0的特征
2.1.1 方差过滤VarianceThreshold

通过特征本身的方差来筛选特征的类,比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能是特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区别就没有作用,所以要优先消除方差为0的特征

VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于阈值的特征,默认为0,即删除所有记录都相同的特征

from sklearn.feature_selection import VarianceThreshold
x_var0 = VarianceThreshold().fit_transform(x)
x_var0.shape
(42000, 708)

可以看到,方差过滤之后剩余的特征还有708个,比之前的784减少了72个,如果我们知道我们需要多少个特征,方差也可以直接帮助我们一次性筛选到位,比如我们希望留下一半的特征,那么我们就把阈值设定为中位数

x_median = VarianceThreshold(x.var().median()).fit_transform(x)
x_median.shape
(42000, 392)

可以看到使用中位数之后,特征值减少了一半

2.1.2方差过滤对模型的影响

使用KNN和随机森林对方差过滤前后的模型分别进行建模分析,查看过滤前后的准确度

(1)导入模块并准备数据

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import cross_val_score

x = data.iloc[:,1:]
y = data.iloc[:,0]

x_median = VarianceThreshold(x.var().median()).fit_transform(x)

(2)KNN方差过滤前

cross_val_score(knn(),x,y,cv=5).mean()
0.9658569700264943
%%timeit  #python中的魔法命令,可以计算运行该cell所需要的时间,运行7次求平均,会严重影响运行时间
cross_val_score(knn(),x,y,cv=5).mean()
33min 58s ± 43.9 s per loop (mean ± std. dev. of 7 runs, 1 lppo each)

(3)KNN方差过滤后

cross_val_score(knn(),x_median,y,cv=5).mean()
0.9659997478150573
%%timeit  #python中的魔法命令,可以计算运行该cell所需要的时间,运行7次求平均,会严重影响运行时间
cross_val_score(knn(),x_median,y,cv=5).mean()
20min ± 4min 55s per  per loop (mean ± std. dev. of 7 runs, 1 lppo each)

可以看出,对于KNN过滤之后的效果十分明显,准确率稍有提升,单平均运行时间减少了10分钟,特征选择过后算法的效率上升了1/3

(4)随机森林方差过滤前

cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
0.9380003861799541
%%timeit
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
18.9 s ± 2.2 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

(5)随机森林方差过滤之后

cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
0.9388098166696807
%%timeit
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x_median,y,cv=5).mean()
17.5 s ± 597 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

可以看到方差过滤前后对随机森林预测的准确率影响不大,对运行时间的影响也不大

这是因为最近邻算法KNN,单棵决策树,支持向量机SVM,神经网络,归回算法,都需要对所有特征进行遍历或升维来进行运算,而随机森林本身就不需要遍历所有的随机变量,只需要选取固定数量的特征就可以进行建模分析,所以方差过滤对其影响不大,

过滤法的主要对象,就是需要遍历特征或升维的算法们,而过滤法的主要目的就是在维持算法表现的前提下,帮助算法们降低运算的成本

2.2 相关性过滤

2.2.1卡方过滤

卡方过滤是专门针对离散型标签(分类问题)的相关过滤,卡方检验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 chi2
from sklearn.feature_selection import SelectKBest
# 假设在这里我们需要300个特征
x_kbest = SelectKBest(chi2,k=300).fit_transform(x_median,y)
x_kbest.shape  # 返回值(42000, 300)
cross_val_score(rfc(n_estimators=10,random_state=0),x_kbest,y,cv=5).mean()
0.9333098667649198

我们可以看到,模型的效果降低了,说明我们在设置k=300时删除了一些与模型相关且有效的特征,可以通过绘制超参数曲线来找到最佳k值

%matplotlib inline
import matplotlib.pyplot as plt
score = []
for i in range(390,200,-10):
    x_kbest = SelectKBest(chi2,k=i).fit_transform(x_median,y)
    once = cross_val_score(rfc(n_estimators=10,random_state=0),x_kbest,y,cv=5).mean()
    score.append(once)
plt.plot(range(390,200,-10),score)
plt.show()
卡方超参数曲线图

通过这条曲线,我们可以看到随着K值得不断增加,模型的表现不断上升,这说明K越大越好,即数据中的特征与标签均相关,

卡方检验的本质是推测两组数组之间的差异,其检验的原假设是“两组数据是相互独立的”,卡方检验返回卡防值和P值两个统计量,一般用p值作为有效性的范围界定,即当P值小于0.01或0.05时,我们认为两组数据是相关的,拒绝原假设

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

从特征工程角度,我们希望选取卡方值很大,p值小于0.05的特征

chivalue,pvalue_chi = chi2(x_median,y)
k = chivalue.shape[0]-(pvalue_chi > 0.05).sum()
k  # 返回值392

可以观察到,所有特征的p值都是0,说明对于digit recognizon这个数据集来说。方差验证已经把所有和标签无关的特征剔除掉了,在这种情况下,舍弃任何一个特征,都会舍弃对模型有用信息,从而使模型表现下降

2.2.2 F检验

F检验,又称齐方差检验,是用来捕捉每个特征和标签之间的线性关系的过滤方法,包含feature_selection.f_classifF分类检验和feature_selection.f_regressionF回归检验

和卡方检验相同,这两个类需要和SelectKBest连用,F检验在数据服从正态分布的时候非常稳定,所以在使用F检验之前,我们可以先对数据进行标准正态化,然后再进行F检验

F检验的本质是寻找两组数据之间的线性关系,其原假设是“数据不存在显著的线性关系”。它返回F值和p值两个统计量。当p值小于0.01或0.05时我们认为两个变量之间存在线性关系,即我们要舍弃p值大于0.01或0.05的值

from sklearn.feature_selection import f_classif
F,pvalues_f = f_classif(x_median,y)
k = F.shape[0]-(pvalues_f>0.05).sum()
k # 返回值392

得到的结果和卡方过滤得到的结论保持一致,没有任何值得特征大于0.01,所有的特征都是和标签相关的,因此我们不需要相关性过滤

2.2.3互信息法

互信息是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法,包含feature_selection.mutual_info_classif(互信息分类)和feature_selection.mutual_info_regression(互信息回归)。互信息法返回“每个特征与目标之间的互信息量的估计”,这个估计量在[0,1]之间取值,为0表示两个变量独立,为1表示两个变量完全相关

from sklearn.feature_selection import mutual_info_classif as MIC
result = MIC(x_median,y)
k = result.shape[0]-sum(result<=0)
k # 返回值392
#X_KBest_mutual = SelectKBest(MIC,k=392).fit_transform(x_median,y)
#cross_val_score(RFC(n_estimators=10,random_state=0),X_KBest_mutual,y,cv=10)

2.3 嵌入法Embedded

嵌入法是一种方算法自己决定使用那些特征的方法,即特征选择和算法训练同时进行,在使用嵌入法时,先使用某些机器学习的算法和模型进行训练,得到每个特征的权值系数,根据权值系数从大到小选择特征,这些权值系数代表特征对标签的重要性程度,比如决策树和树的集成模型中的feature_importances_属性,可以列出各个特征对树的建立贡献,因此相对于过滤法,嵌入法的结果会更加精确到模型的效用本身,对于提高模型效力有更好的效果

但是嵌入法返回的是权值系数,我们无法和卡方检验和F检验,通过筛选P值的方式来进行筛选,我们并不知道权值系数处于一个什么样的范围是最好的,因此我们可以使用学习曲线的方式来选取最优权值参数

feature_selection.SelectFromModel(estimator,threshold=None)

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

参数 说明
estimator 使用的模型评估器,只要是带feature_importances_和coef_的都可以使用
threshold 特征重要性的阈值,重要性低于这个阈值的特征都将被删除
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.feature_selection import SelectFromModel

RFC_ = RFC(n_estimators=10,random_state=0)
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(x,y)
X_embedded.shape  # 返回值(42000, 47)

可以看到特征数降为47,但是这样设定阈值是不准确的,我们可以通过绘制学习曲线来找到最优的阈值

#==========【TIME WARNING:10 MINS】============#
import numpy as pd
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.figure(figsize=(20,5))
plt.plot(threshold,score)
plt.xticks(threshold)
plt.show()
嵌入法全局阈值

从图像上来看,随着阈值越来越高,模型的效果越来越差,被删除的特征值越来越多,信息损失也越来越大,但是在0.00134之前,模型的效果都可以维持在0.93以上,因此我们可以继续选定一个范围,细化学习曲线来找到最佳值

score2 = []
for i in np.linspace(0,0.00134,20):
    X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(x,y)
    once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
    score2.append(once)
plt.figure(figsize=(20,5))
plt.plot(np.linspace(0,0.00134,20),score2)
plt.xticks(np.linspace(0,0.00134,20))
plt.show()
嵌入法局部阈值

从图像上可以看到阈值为0.000564时模型的效果是最好的,我们可以把0.000564带入模型看一下效果

from sklearn.feature_selection import SelectFromModel
X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(x,y)
cross_val_score(RFC_,X_embedded,y,cv=5).mean()
0.9408335415056387

可以看到模型的准确率升高为94%点多,因此,比起要考虑很多统计量的过滤法来说,前复发可能是更有效的一种方法,然而,在算法本身复杂的时候,过滤法的计算量远远比嵌入法快,所以在大型数据中,还是要优先考虑过滤法

2.4 包装法Wrapper

包装法也是特征选择和算法同时进行的方法,与嵌入法相同的是包装法也是通过模型训练之后的feature_importantances_或者coef_来进行特征的选择,与嵌入法不同的是包装法不需要我们指定阈值,包装法通过coef_属性或feature_importantances_属性获得每个特征的重要性,然后从当前的一组特征中修剪最不重要的特征。在修剪的集合上地柜地重复该过程,直到最终到达所需数量的要选择的特征

包装法是最能保证模型效果的特征选择方法,但是包装法要使用特征子集进行多次训练,所以包装法需要的计算成本是最高的

feature_selection.RFE(estimator,n_features_to_select=None,step=1,verbose=0)
feature_selection.RFECV(estimator,n_features_to_select=None,step=1,verbose=0,cv=5)
参数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=50,step=50).fit(x,y)
#selector.support_.sum()   support_属性返回特征选择的布尔矩阵
#selector.ranking_    ranking_属性返回特征的按次数迭代中综合重要性的排名
X_wrapper = selector.transform(x)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
0.9056911999667074

使用超参数曲线寻找最优的特征保留数目

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()
包装法超参数曲线

明显可以看出,在包装法下,应用50个特征时,模型的表现就已经达到了90%,比嵌入法和过滤法都高效很多,在特征数相同的情况下,包装法在效果上匹敌嵌入法,同样我们也可以进一步细化超参数曲线来找到最优的特征数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容