数据预处理与特征工程

1.数据预处理

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

可能面对的问题:

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

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

1.1 数据无量纲化

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

1.1.1 数据归一化preprocessing.MinMaxScaler

将数据压缩到指定的范围,默认为[0,1],也可以通过参数feature_range把数据压缩到其他范围
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)

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 ∗ = 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 = 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()
AgeSexEmbarkedSurvived
022.0maleSNo
138.0femaleCYes
226.0femaleSYes
335.0femaleSYes
435.0maleSNo

(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()
AgeSexEmbarkedSurvived
022.0maleS0
138.0femaleC2
226.0femaleS2
335.0femaleS2
435.0maleS0
特征编码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()
AgeSexEmbarkedSurvived
022.0male2.00
138.0female0.02
226.0female2.02
335.0female2.02
435.0male2.00
独热编码:创建特征哑变量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()
AgeSurvivedfemalemaleEmbarked_CEmbarked_QEmbarked_S
022.000.01.00.00.01.0
138.021.00.01.00.00.0
226.021.00.00.00.01.0
335.021.00.00.00.01.0
435.000.01.00.00.01.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_classifF检验分类,只能捕捉线性相关,要求数据服从正态分布追求P值小于显著性水平的特征
f_regressionF检验回归,只能捕捉线性相关,要求数据服从正太分布追求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%,比嵌入法和过滤法都高效很多,在特征数相同的情况下,包装法在效果上匹敌嵌入法,同样我们也可以进一步细化超参数曲线来找到最优的特征数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值