机器学习之特征选择(Feature Selection)

您所在的位置:网站首页 f检验f值多大算好 机器学习之特征选择(Feature Selection)

机器学习之特征选择(Feature Selection)

2023-11-30 20:38| 来源: 网络整理| 查看: 265

1 引言

  特征提取和特征选择作为机器学习的重点内容,可以将原始数据转换为更能代表预测模型的潜在问题和特征的过程,可以通过挑选最相关的特征,提取特征和创造特征来实现。要想学习特征选择必然要了解什么是特征提取和特征创造,得到数据的特征之后对特征进行精炼,这时候就要用到特征选择。本文主要介绍特征选择的三种方法:过滤法(filter)、包装法(wrapper)和嵌入法(embedded)。

特征提取(Feature Extraction):从文字,图像,声音等其他非结构化数据中提取新信息作为特征。比如说,从淘宝宝贝的名称中提取出产品类别,产品颜色,是否是网红产品等等。

 

特征创造(Feature Creation):把现有特征进行组合,或互相计算,得到新的特征。比如说,我们有一列特征是速度,一列特征是距离,我们就可以通过让两列相处,创造新的特征:通过距离所花的时间。

 

特征选择(Feature Selection):从所有的特征中,选择出有意义,对模型有帮助的特征,以避免必须将所有特征都导入模型去训练的情况。

2 Filter过滤法

  过滤法可以理解为在机器学习算法之前的预处理,过滤法特征选择的过程完全独立与任何机器学习算法。根据对特征经过统计检验之后得到的分数,来筛选掉一些相对来说无用的特征,从而优化特征集。

 

过滤法适用场景:在需要遍历特征或升维的算法之前,对特征进行过滤。

过滤法的目的:在维持算法表现的前提下,帮助算法降低计算成本。

2.1 方差过滤

  Variance Threshold是通过特征本身方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。所以无论接下来的特征工程要做什么,都要优先消除方差为0的特征。VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于threshold的特征,不填默认为0,即删除所有的记录都相同的特征。下面代码简单的实现了方差过滤:

import pandas as pd from sklearn.feature_selection import VarianceThreshold data = pd.read_csv(r"./train.csv") x = data.iloc[:,1:] y = data.iloc[:,0] print(x.shape) selector = VarianceThreshold() x_var0 = selector.fit_transform(x) print(x_var0.shape)

   从结果中可以看到原本数据中有784个特征,经过阈值为 0 的方差过滤之后,剩下708个特征,也就是说之前有76个特征的方差都为0。剩下的708个特征还是比较多的,并不能满足我们的需求,此时我们还需要进一步的特征选择。由于单纯调整阈值比较抽象,我们并不知道特定阈值下会留下多少个特征,留下特征过多或者过少都对我们的结果不利,所以我们可以留下指定数量的特征,比如留下一半的特征,找到特征方差的中位数,再将这个中位数作为 threshold 的值就可以让特征总数减半,代码如下:

import pandas as pd import numpy as np from sklearn.feature_selection import VarianceThreshold data = pd.read_csv(r"./train.csv") x = data.iloc[:,1:] y = data.iloc[:,0] print(x.shape) selector = VarianceThreshold(np.median(x.var().values)) x_feature_selection = selector.fit_transform(x) print(x_feature_selection.shape)

   如果特征是二分类,特征的取值就是伯努利随机变量,这些变量的方差计算公式为:Var[X] = p (1 - p),其中 X 为特征矩阵,p为二分类特征中的一类在这个特征中所占的概率。那么假设 p = 0.8,即二分类中某种分类占到80%以上的时候删除特征。代码如下

import pandas as pd import numpy as np from sklearn.feature_selection import VarianceThreshold data = pd.read_csv(r"./train.csv") x = data.iloc[:,1:] y = data.iloc[:,0] print(x.shape) selector = VarianceThreshold(0.8 *(1-0.8)) x_feature_selection = selector.fit_transform(x) print(x_feature_selection.shape)

   K-近邻算法(KNN)是一种比较简单的分类算法,其原理是利用每个样本到其他样本点的距离来判断每个样本点的相似度,然后对样本进行分类。KNN必须遍历每个特征和样本,因而特征越多,KNN所需要的计算力也就越大。

  随机森林或随机决策森林是用于分类,回归和其他任务的集成学习方法,其通过在训练时构建多个决策树并输出作为类的模式(分类)或平均预测(回归)的类来操作。个别树木。随机决策森林纠正决策树过度拟合其训练集的习惯。随机森林随机的选取特征进行分值,本身的运算非常迅速。

  实验证明,对特征进行方差过滤之后,KNN的准确率稍有提升,运行时间降低了三分之一。随机森林的准确率略低于KNN,但是花费的算力非常少,不到KNN计算时间的百分之 1 。另外随机森林的准确率略微上升,运行时间并没与什么变化。因此方差过滤并不是适用于所有的算法,因为过滤之后模型可能变好也可能变性能下降。我们就需要针对数据集去进行尝试,也就是调参,选出最优的参数,画学习曲线就可以找到比较好的参数点。但是现实中一般不会花费太多时间在方差过滤的调参上,而是使用阈值为 0 或者阈值很小的方差进行过滤,消除一些明显用不到的特征然后选取其他的特征选择方法继续削减特征数量。

2.2 相关性过滤

  一般情况下特征如果和标签的相关性比较大的话,这样的特征能够为我们提供大量的信息。如果特征与标签无关,只会白白浪费我们的算力,还可能给模型带来噪声。在 sklearn 中有三种常用的方法来评判特征和标签之间的相关性:卡方、F检验和互信息。

卡方过滤

  卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类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()

  K值变化时,模型的评分也会跟着变化,手动去调整一个一个参数的话效率非常低,我们可以使用学习曲线来获得一个最优的超参数K。代码如下:

import pandas as pd import numpy as np from sklearn.feature_selection import VarianceThreshold 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 import matplotlib.pyplot as plt data = pd.read_csv(r"./train.csv") x = data.iloc[:,1:] y = data.iloc[:,0] # print(x.shape) selector = VarianceThreshold(np.median(x.var().values)) x_fsvar = selector.fit_transform(x) 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()

  从曲线中我们可以看到,随着K值不断的在呢个价模型的表现不断上升,这说明K越大越好,数据中所有的特征都是和标签相关的。但是这个程序运行时间比较长,我们可以用另一种更好的方法选择 K :看 p 值选K。

  卡方阿金艳的本质是推测数据之间的差异,卡方检验返回卡方值和 P 值两个统计量,其中卡方值很难界定有效的范围,而 p 值我们一般使用 0.01 或 0.05 作为显著性水平,即p值判断的边界。

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

  卡方值大,p值小于0.05的特征是和标签相关联的特征。调用 SelectKBest,可以直接从chi实例化后的模型中获取各个特征所对应的卡方值和 p 值。我们只需要算出来p值大于0.05 的特征有几个,这个个数就是我们想要得到的K值。这里得到的 p 值全为 0,也就是说对于该数据集,方差过滤已经把所有和标签无关的特征都剔除了。 

chivalue, pvalues_chi = chi2(X_fsvar,y)print(chivalue)print(pvalues_chi) #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() F检验

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

  和卡方检验一样,这两个类需要和类SelectKBest连用,并且我们也可以直接通过输出的统计量来判断我们到底要设置一个什么样的K。需要注意的是,F检验在数据服从正态分布时效果会非常稳定,因此如果使用F检验过滤,我们会先将数据转换成服从正态分布的方式。

  F检验的本质是寻找两组数据之间的线性关系,其原假设是”数据不存在显著的线性关系“。它返回F值和p值两个统计量。和卡方过滤一样,我们希望选取p值小于 0.05 或 0.01 的特征,这些特征与标签时显著线性相关的,而p值大于0.05或0.01的特征则被我们认为是和标签没有显著线性关系的特征,应该被删除。以F检验的分类为例,我们继续在数字数据集上来进行特征选择:

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

 

  得到的结论和我们用卡方过滤得到的结论一模一样:没有任何特征的p值大于0.01,所有的特征都是和标签相关,因此不需要进行相关性过滤。

互信息法

  互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。和F检验相似,它既可以做回归也可以做分类,并且包含两个类feature_selection.mutual_info_classif(互信息分类)和feature_selection.mutual_info_regression(互信息回归)。这两个类的用法和参数都和F检验一模一样,不过互信息法比F检验更加强大,F检验只能够找出线性关系,而互信息法可以找出任意关系。

  互信息法不返回 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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3