当数据预处理完成后,我们需要进行特征选择,即选择有意义的特征输入机器学习的算法和模型进行训练。特征选择主要有两个功能:
通常来说,从两个方面考虑来选择特征:
Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。
过滤式方法(Filter)通常是独立地选择特征,这可能会忽略特征组合之间的相关性。
使用方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。使用feature_selection库的VarianceThreshold类来选择特征的代码如下:
from sklearn.feature_selection import VarianceThreshold
# 方差选择法,返回值为特征选择后的数据
# 参数threshold为方差的阈值
VarianceThreshold(threshold=3).fit_transform(iris.data)
# iris.data为鸢尾花数据
使用相关系数法,先要计算各个特征对目标值的相关系数以及相关系数的P值。用feature_selection库的SelectKBest类结合相关系数来选择特征的代码如下:
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
#参数k为选择的特征个数
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
经典的卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量:
χ 2 = ∑ ( A − E ) 2 E \chi^{2}=\frac{\sum (A-E)^{2}}{E} χ2=E∑(A−E)2
用feature_selection库的SelectKBest类结合卡方检验来选择特征的代码如下:
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
经典的互信息也是评价定性自变量对定性因变量的相关性的,互信息计算公式如下:
I ( X ; Y ) = ∑ x ϵ X ∑ y ϵ Y p ( x , y ) l o g p ( x , y ) p ( x ) p ( y ) ) I(X;Y)= \sum_{x\epsilon X} \sum_{y\epsilon Y}p(x,y)log \frac{p(x,y)}{p(x)p(y))} I(X;Y)=xϵX∑yϵY∑p(x,y)logp(x)p(y))p(x,y)
若想把互信息直接用于特征选择其实不是太方便:1、它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;2、对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,取值区间在[0,1]。
使用feature_selection库的SelectKBest类结合最大信息系数法来选择特征的代码如下:
from sklearn.feature_selection import SelectKBest
from minepy import MINE
#由于MINE的设计不是函数式的,定义mic方法将其为函数式的,返回一个二元组,二元组的第2项设置成固定的P值0.5
def mic(x, y):
m = MINE()
m.compute_score(x, y)
return (m.mic(), 0.5)
#选择K个最好的特征,返回特征选择后的数据
SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
递归特征消除的主要思想是反复的构建模型(如SVM或者回归模型)然后选出最差的(或者最好的)的特征(可以根据系数来选),把选出来的特征放到一边,然后在剩余的特征上重复这个过程,直到所有特征都遍历了。这个过程中特征被消除的次序就是特征的排序。因此,这是一种寻找最优特征子集的贪心算法。
RFE的稳定性很大程度上取决于在迭代的时候底层用哪种模型。例如,假如RFE采用的普通的回归,没有经过正则化的回归是不稳定的,那么RFE就是不稳定的;假如采用的是Ridge,而用Ridge正则化的回归是稳定的,那么RFE就是稳定的。
使用feature_selection库的RFE类来选择特征的代码如下:
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法,返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
基于惩罚项的特征选择法其实是基于正则的特征选择法。正则化就是把额外的约束或者惩罚项加到已有模型(损失函数)上,以防止过拟合并提高泛化能力。损失函数由原来的 E ( X , Y ) E(X,Y) E(X,Y)变为 E ( X , Y ) + α ∣ ∣ w ∣ ∣ E(X,Y)+\alpha||w|| E(X,Y)+α∣∣w∣∣,w是模型系数组成的向量(有些地方也叫参数parameter,coefficients),||·||一般是 L 1 L_{1} L1或者 L 2 L_{2} L2范数, α \alpha α是一个可调的参数,控制着正则化的强度。当用在线性模型上时, L 1 L_{1} L1正则化和 L 2 L_{2} L2正则化也称为Lasso和Ridge。
L 1 L_{1} L1正则化将系数w的l1范数作为惩罚项加到损失函数上,由于正则项非零,这就迫使那些弱的特征所对应的系数变成0。因此 L 1 L_{1} L1正则化往往会使学到的模型很稀疏(系数w经常为0),这个特性使得 L 1 L_{1} L1正则化成为一种很好的特征选择方法。
L 2 L_{2} L2正则化将系数向量的 L 2 L_{2} L2范数添加到了损失函数中。由于 L 2 L_{2} L2惩罚项中系数是二次方的,这使得 L 2 L_{2} L2和 L 1 L_{1} L1有着诸多差异,最明显的一点就是, L 2 L_{2} L2正则化会让系数的取值变得平均。对于关联特征,这意味着他们能够获得更相近的对应系数。以Y=X1+X2为例,假设X1和X2具有很强的关联,如果用L1正则化,不论学到的模型是Y=X1+X2还是Y=2X1,惩罚都是一样的,都是2 alpha。但是对于L2来说,第一个模型的惩罚项是2 α \alpha α,但第二个模型的是4* α \alpha α。可以看出,系数之和为常数时,各系数相等时惩罚是最小的,所以才有了L2会让各个系数趋于相同的特点。
树模型有准确率高、鲁棒性好、易于使用等优点,这使得它成为了目前最流行的机器学习算法之一。以下以随机森林为例。
随机森林由多个决策树构成。决策树中的每一个节点都是关于某个特征的条件,为的是将数据集按照不同的响应变量进行分裂。利用不纯度可以确定节点基于哪个特征进行分裂,对于分类问题,通常采用基尼系数或者信息增益 ,对于回归问题,通常采用的是方差或者最小二乘拟合。当训练决策树的时候,可以计算出每个特征减少了多少树的不纯度。对于一个决策树森林来说,可以算出每个特征平均减少了多少不纯度,并把它平均减少的不纯度作为特征选择的值。
另一种常用的特征选择方法就是直接度量每个特征对模型精确率的影响。主要思路是打乱每个特征的特征值顺序,并且度量顺序变动对模型的精确率的影响。很明显,对于不重要的变量来说,打乱顺序对模型的精确率影响不会太大,但是对于重要的变量来说,打乱顺序就会降低模型的精确率。
查看每个特征作为节点分裂依据的次数,次数越多则认为这个特征越重要。根据次数对特征进行排序。
参考:
https://www.cnblogs.com/bonelee/p/8632866.html
https://blog.csdn.net/akenseren/article/details/80816210
卡方分布
https://blog.csdn.net/bitcarmanlee/article/details/52279907