数据预处理,特征选择的目的是改善数据质量,体现数据的本质特征,降低计算成本,提升模型的表现。
特征选择–主要分为三个模块:
- 特征提取(Features Extraction):如从文本型数据提取日期型数据;从非结构化数据(文本,视频,音频等)提取数据。如:Web爬取等;
- 特征创建(Features Creation):通过组合,计算等方法,得到原本不存在的特征(必须是合理的),比如:使用(数量*单价-折扣)得到销售额字段;
- 特征选择(Features Selection):从所有特征中,选择对当前模型有价值的特征,但必须要经过验证。
特征选择是独立于任何机器学习算法的,往往是根据各种统计检验的分值 以及相关性指标来选择特征。
- 特征选择与模型应用的基本流程:
全部特征有哪些–》通过统计检验获取最佳特征子集(无创造新特征)–》通过算法进行训练–》模型评估–》模型应用
创造新特征:在数据整理的时候,
import pandas as pd data=pd.read_csv("digit recognizor.csv")# 手写体数字特征提取
X=data.iloc[:,1:] # 前面的标签不要
y=data.iloc[:,0] y.unique() # 想要知道每个数据上有多少数据
# 体现0-9共十个数字每个数字有多少个样本 a=data.groupby("label").count()
一、Filter过滤法
1、方差过滤
方差过滤:消除方差为0的数据。
为什么使用方差过滤?
- 方差用来衡量随机变量或数据的离散程度(统计),或者衡量随机变量与数学期望(如均值)之间的偏离程度。
- 方差小,表示样本在特征上基本无差异,这种情况对于样本区分的价值不高。
- 消除方差为0的特征是特征工程的重要任务。使用threshold来进行筛选,默认为0。
在机器学习的数据预处理的过程中常常会是使用到过滤法,而方差过滤是过滤法之一。所谓的方差过滤就是过滤掉那些特征方差较小的特征。
比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。
所以可以设置一个过滤的阈值,过滤掉那些方差小的特征,从而达到特征筛选的目的。
在 sklearn中可以调用from sklearn.feature_selection import VarianceThreshold
类实现方差过滤。
以手写识别为例子:
from sklearn.feature_selection import VarianceThreshold selector=VarianceThreshold() # 实例化,默认方差为0 X_var0=selector.fit_transform(X) # 获取具有特定价值的新特征矩阵 X_var0.shape # 使用方差进行过滤时,过滤掉了80+的数据
import numpy as np np.median(X.var().values)
# 以特征方差中位数为阈值,考察特征选择结果 X_fsvar=VarianceThreshold(np.median(X.var().values)).fit_transform(X)
# 若特征是伯努利的随机变量,假设p=0.8 :表示如果某一种分类站到80%以上时,要删除特征 X_bvar=VarianceThreshold(.8*(1-0.8)).fit_transform(X) X_bvar.shape # (42000, 685) 大概消除了100个特征
from sklearn.feature_selection import VarianceThreshold from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.neighbors import KNeighborsClassifier as KNN from sklearn.model_selection import cross_val_score # 交叉验证
利用KNN和随机森林对全部特征,和以方差中位数为阈值的特征进行比较:
(1)使用KNN进行考察
过滤:特征选择。
比较KNN在方差过滤前后的准确度:
# KNN在方差过滤之前 cross_val_score(KNN(),X,y,cv=5).mean() # 0.9658 %%timeit # 计算运行时间 cross_val_score(KNN(),X,y,cv=5).mean()
# KNN在方差过滤之后 cross_val_score(KNN(),X_fsvar,y,cv=5).mean() # 0.966 %%timeit # 计算运行时间 cross_val_score(KNN(),X_fsvar,y,cv=5).mean()
(2)使用随机森林(RFC)进行考察
# 随机森林考察特征选择效果 %%timeit cross_val_score(RFC(n_estimators=10,random_state=0),X,y,cv=5).mean() %%timeit cross_val_score(RFC(n_estimators=10,random_state=0),X_fsvar,y,cv=5).mean()
使用方差过滤后的特征对KNN和RFC的影响:
- 对两种算法的检测结果,可看出其模型精度是上升的,说明方差过滤是有效的,即将随机模式设置为random——state=0之后大部分噪声都被过滤掉了。
- 阈值较小被过滤的特征也会更少,模型表现不同会受影响,运行时间总体会少,但有时不明显。
- 阈值较大被过滤的特征相对较多,模型表现可能会更好,因为噪声在某些算法下可能被过滤了,但也有可能是相反的,在运行时间方面肯定会降低。
tempdf=pd.DataFrame(X,y) tempdf.reset_index(inplace=True) tempdf
r1=PearsonFirst(tempdf['label'],tempdfempdf['pixel400']) # 使用公式一计算X与Y的相关系数 r2=PearsonFirst(tempdf['label'],tempdfempdf['pixel400']) # 使用公式二计算X与Y的相关系数 tempdf.corr(method="pearson") # 耗时太长,了解即可
2、相关性过滤
选出与标签相关且有意义的特征。
(1)卡方过滤
- 专门针对离散型的标签(分类问题,如0,1,2…),使用sklearn.feature_selection.chi2计算每个非负特征(标准化,归一化过程)和标签之间的卡方统计量。根据统计量进行排名,并结合sklearn.feature_selection.chi2输入评选标准来选择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
(2) 用随机森林进行比较特征选择
# 用随机森林进行比较特征选择 cross_val_score(RFC(n_estimators=20,random_state=0),X_fschi,y,cv=10).mean()
计算时间:
(3)选取超参数
k到底选择多大最合适?利用算法+学习曲线进行判断
# 选取超参数 %matplotlib inline import matplotlib.pylab 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(390,200,-10),score) plt.show()
如下图,最高大约在94%,因此K值大约选在380位置处。
对应score如下:
从特征工程的角度,选取卡方值较大,P值小于0.05的特征 ,即与标签有较大相关性。返回k值进行检验
chivalue,pyvalues_chi=chi2(X_fsvar,y) # 输入特征矩阵与标签 k=chivalue.shape[0]-(pyvalues_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 # n_estimators=10 选取10颗树,使用RFC来进行交叉验证
k=chivalue.shape[0]-(pvalues_chi>0.05).sum() # 去除与标签无关的相关值 # 大于0.05表示与标签无关
求出K值,就可以用在下面的代码中:
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()
如果使用全特征呢?
# 如果使用全特征呢? chivalue,pvalues_chi=chi2(X,y) # 输入特征矩阵和标签 k=chivalue.shape[0]-(pvalues_chi>0.05).sum() # 去除与标签无关的相关值 k
可以看到全特征计算出的K值更多:↑
但是准确度小于中位数特征值处理后的准确度:↑
总结卡方检验的作用:
推测两组数据之间的差异,原假设是:两组数据之间是相互独立的。返回卡方值和P值这两个统计量。
P值 | <0.05或者0.01 | >0.05或者0.01 |
数据差异 | 差异不是自然形成的 | 差异是自然形成的 |
相关性 | 两组数据是相关的 | 两组数据是相互独立的 |
原假设 | 拒绝原假设 | 接受原假设 |
从特征工程的角度,选取卡方值较大,P值小于0.05的特征,即与标签有较大相关性。返回K值进行检验。
调用SelectKBest之前,直接从chi2实例化后的模型中获得各个特征所对应的卡方值和P值。
4)F检验
- F检验是用来捕捉每个特征与标签之间的线性关系的过滤方法。
- 可回归,可分类,故包含(离散型变量
feature_selection.f_classif
)和(连续型变量feature_selection.f_regression
)两类。 - 需要与
SelectKBest
联合使用,即也需要有超参数 - 在正态分布情况下效果稳定
- 原假设:数据之间不存在显著的线性关系。返回F和P值。小于0。05或者0.01代表显著性相关
from sklearn.feature_selection import f_classif F,pvalues_f=f_classif(X_fsvar,y) F
P值当中存在大量的0:↓
接着求出K值后,代入随机森林当中做计算:
X_fsF=SelectKBest(f_classif,k=k).fit_transform(X_fsvar,y) cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
(5)互信息法
- 两个随机变量的互信息(mutual information)是变量之间相互依赖性的量度
- 互信息度量是两个随机变量共享的信息——知道随机变量x,对随机变量Y的不确定性减少的程度(或者知道随机变量Y,对随机变量X的不确定性减少的程度),用I(X:Y)表示
- 特征与标签之间可能存在任意关系(线性和非线性)
- 可回归,可分类,feature_selection.mutual_info_classif(互信息分类)和feature_selection.mutual_info_regression(互信息回归)
- 不返回P或者F,返回的是每个特征与目标特征之间互信息量的估计值,【0,1】之间取值
#X_fsvar 利用中位数取的特征,使用的是互信息法的方式 from sklearn.feature_selection import mutual_info_classif as MIC result = MIC(X_fsvar,y) result
k = result.shape[0] - sum(result <= 0) k
根据算出的K值,计算交叉验证得到的准确度:
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()