特征选择
对于模型的训练来说,当输入的数据维度过大会消耗大量的时间,而且也不是所有的属性对于模型性能的提升都是有益的,无关的属性输入反而还会降低模型的性能。在此情形下,需要对属性进行选择。
方差过滤
一些属性的值在某一常值附近波动极小,甚至就是常值,也就是说这些属性的方差值很小。这些属性对于映射关系的建立几乎是没有用的,在这些属性上没有区分度。如果提前对数据进行方差过滤,就可以筛选出这样的属性减少模型的输入维度。
在Sklearn中,方差过滤的类为VarianceThreshold。
from sklearn.feature_selection import varianceThreshold
import numpy as np
selector = VarianceThreshold()//默认方差值为0
x_var = selector.fit_transfrom()
x_fsvar = VarianceThreshold(np.median(x.var().values).fit_transform(x)//选出一半的特征
如果特征是伯努利分布,则方差为:
p
(
1
−
p
)
p(1-p)
p(1−p)
阈值很小,被过滤的特征数较少 | 阈值较大,被过滤的特征数较多 | |
---|---|---|
模型表现 | 不会有太大影响 | 可能变好,代表被滤掉的特征大部分是噪音;可能变坏,代表被滤掉的有一些有用信息 |
运行时间 | 可能降低模型运行时间 | 一定能够降低模型运行时间 |
卡方过滤
卡方过滤针对特征和离散型数据(分类)之间的相关性进行过滤,卡方统计原假设两数据之间独立不具有相关性,其要求特征非负。
在SKlearn中,卡方过滤类为ch2
from sklearn.feature_selection import Ch2
from sklearn.feature_selection import SelectKBest
from sklearn.model_selection import cross_val_score
x_fschi = selectKBest(ch2,k=300).fit_transform(x)//k为特征选择后个数
crosss_val_score(RFC(n_estimators=10,random_state=0),x_fschi,y,cv=5).mean()
在经过卡方检验选择后,模型的性能可能会提升,说明检验滤除了特征噪音;也有可能降低,说明滤除了有用特征。此时可以利用学习曲线来确定特征个数K。
通过学习曲线寻找最佳K值:
score = [ ]
for i in range(390,200,-10):
x_fschi = selectKBest(chi2, k = i).fit_transform(x_fsvar,y)
onece = cross_val_score(RFC(n_estimators=10,random_stade=0),x_fschi,y,cv=5).mean( )
score.append(once)
plt.plot(range(350,250,-10),score)
plt.show()
卡方检验返回两个值,卡方值和P,其中卡方值难以界定有效范围,P值取0.01或0.05作为显著性边界–拒绝还是接受原假设。
chivalue,pvalues_chi = chi2(x_fsvar,y)
chivalue
pvalues_chi
k = chivalue.shape[0]-(pvalues_chi > 0.05).sum()
P<=0.05或0.01 | p>0.05或0.01 | |
---|---|---|
数据差异 | 差异不是自然形成 | 差异自然形成 |
相关性 | 两组数据线性相关 | 不具有线性相关 |
原假设 | 拒绝原假设 | 接收原假设 |
F检验
F检验捕捉每个特征与标签间的线性关系,其原假设:数据间不存在显著的线性关系。既可以应用于连续性标签(回归),也可以应用于离散型标签(分类),其对应的类分别为feature_selection.f_classify和feature_selection.f_regression。
from sklearn.feature_selection import f_classif
from sklearn.feature_selection import SelectKBest
from sklearn.model_selection import cross_val_score
x_f = selectKBest(f_classif,k=300).fit_transform(x)//k为特征选择后个数
crosss_val_score(RFC(n_estimators=10,random_state=0),x_f,y,cv=5).mean()
F,pvalue_f = f_classif(x_fsvar,y)
print(F)
print(pvalue_f)
k = F.shape[0]-(pvalues_f > 0.05).sum()
互信息法检验
互信息的概念来自于信息熵,可以捕获特征与标签间的任意关系,包括线性与非线性,其返回特征与标签间的互信息估计值在0-1间,0表示两数据相互独立,1表示两数据完全相关。
互信息计算公式如下:
I
(
X
:
Y
)
=
∑
y
∈
Y
∑
x
∈
X
p
(
x
,
y
)
l
o
g
(
p
(
x
,
y
)
p
(
x
)
p
(
y
)
)
I(X:Y)=\sum_{y\in Y}\sum_{x\in X}p(x,y)log(\frac {p(x,y)}{p(x)p(y)})
I(X:Y)=y∈Y∑x∈X∑p(x,y)log(p(x)p(y)p(x,y))
对于连续型变量:
I
(
X
,
Y
)
=
∫
y
∫
x
p
(
x
,
y
)
l
o
g
(
p
(
x
,
y
)
p
(
x
)
p
(
y
)
)
d
x
d
y
I(X,Y)=\int_y\int_xp(x,y)log(\frac{p(x,y)}{p(x){p(y)}})dxdy
I(X,Y)=∫y∫xp(x,y)log(p(x)p(y)p(x,y))dxdy
对于离散型变量可以将其转化为KL散度
I
(
X
:
Y
)
=
∑
y
∈
Y
∑
x
∈
X
p
(
x
,
y
)
l
o
g
(
p
(
x
,
y
)
p
(
x
)
p
(
y
)
)
=
D
K
L
(
p
(
x
,
y
)
∣
∣
p
(
x
)
p
(
y
)
)
I(X:Y)=\sum_{y\in Y}\sum_{x\in X}p(x,y)log(\frac {p(x,y)}{p(x)p(y)})=D_{KL}(p(x,y)||p(x)p(y))
I(X:Y)=y∈Y∑x∈X∑p(x,y)log(p(x)p(y)p(x,y))=DKL(p(x,y)∣∣p(x)p(y))
如果
x
x
x和
y
y
y是相互独立的随机变量,则
p
(
x
,
y
)
=
p
(
x
)
p
(
y
)
p(x,y)=p(x)p(y)
p(x,y)=p(x)p(y),那么
I
(
X
:
Y
)
=
0
I(X:Y)=0
I(X:Y)=0.因此,
I
(
X
:
Y
)
I(X:Y)
I(X:Y)越大,则两变量相关性越高。
互信息法用法和F检验类似。
from sklearn.feature_selection import mutual_info_classif
嵌入法
嵌入法让算法自己决定使用哪些特征,特征选择和算法训练同时进行,先使用机器学习算法进行训练得到各特征的权值系数,根据权值系数从大到小选择特征。
使用如下:
from sklearn.feature_selection import selectionFromModel
RFC = RFC(n_estimators = 10,random_state=10)
x_embeded = selectionFromModel(RFC,threshold = 0.05).fit(x,y)
对于嵌入法来说,很难确定每个特征的贡献度,其阈值难以确定,此时就需要学习曲线。
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_embeded = selectFromModel(RFC_,threshold=i).fit_transform(x,y)
once = cross_val_score(RFC_,x_embeded,y,cv=5).mean()
score.append(onece)
plt.plot(threshold,score)
plt.show()
包装法
包装法和嵌入法类似,只是包装法使用目标函数进行最佳特征选择。
使用如下:
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_
学习曲线:
score = []
for i in range(1,751,50):
x_warper = RFE(RFC_,n_feature_to_select = i, step = 50).fit_transform(x,y)
onece = cross_val_score(RFC_,x_warper,y cv=5).mean()
score.append(onece)
plt.figure(figsize = [20,5])
plt.plot(range(1,751,50),score)
plt.xticks(range(1,751,50))
plt.show()
总结
在机器学习中,数据是性能的天花板,其重要性远大于算法。特征工程可以使得数据更符合算法的处理需求,在一定程度上提高算法的性能。在特征工程中可以按照缩放、缺失值处理、方差过滤等一系列检验再应用嵌入法包装法的步骤。