前边文章讲了特征工程的定义、特征处理和特征转换;本节继续特征特征相关的内容,主要讲特征的选择。
特征选择是在数据分析和建模中最常用的特征降维手段。过程简单粗暴,即映射函数直接将不重要的特征删除,不过这样会造成特征信息的丢失,不利于模型的精度。当然,由于数据分析以抓住主要影响因子为主,变量越少越有利于分析,因此特征选择常用语统计分析模型中;在超高维数据分析或者建模预处理中也会经常使用。
**特征选择的目标 **:
特征选择一般由三种方法:过滤法、包装法、嵌入法
过滤法:Filter,特征变量与目标变量之间的关系
按照发散性或者相关性对各个特征进行评分,通过设置阈值或者待选择阈值的个数来选择特征
相关系数、卡方检验、信息增益、互信息等方法
包装法:Wrapper,通过目标函数来决定是否加入特征变量
根据目标函数每次选择若干个特征,或者排除若干个特征
嵌入法:Embedded,学习器自身自动选择特征
使用机器学习的某些算法和模型进行训练,得到各个特征的权值系数,并根据系数从大到小选择特征。类似于过滤,区别在于嵌入法是通过模型训练来确定特征的优劣
正则化、熵、信息增益等方法
我们统一使用iris数据集进行验证
import pandas as pd
from sklearn.datasets import load_iris
import numpy as np
iris = load_iris()
X = iris.data
y = iris.target
卡方检验(过滤法)
是过滤法的一种,检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,
构建统计量: x 2 = ( A − E ) 2 E x^2 = \frac{(A -E)^2}{E} x2=E(A−E)2
这个统计量的含义简而言之就是自变量对因变量的相关性。选择卡方值排在前面的K个特征作为最终的特征选择
A是实际数量、E是期望的数量
卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类 feature_selection.chi2 计算每个非负特征和标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
chi2(X,y)
#(array([ 10.82, 3.71, 116.31, 67.05]),
#array([4.48e-03, 1.56e-01, 5.53e-26, 2.76e-15]))
卡方检验的本质是推测两组数据之间的差异,其检验的原假设是”两组数据是相互独立的”。卡方检验返回卡方值和P值两个统计量,其中卡方值很难界定有效的范围,而p值,我们一般使用0.01或0.05作为显著性水平,即p值判断的边界。
我们还可以结合 feature_selection.SelectKBest 这个可以输入”评分标准“来选出前K个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。
chi = SelectKBest(score_func=chi2, k=2)
chi.fit(X, y)
chi.scores_
#array([ 10.82, 3.71, 116.31, 67.05])
从结果可以看出,P值越小的特征,卡方值越大;所以我们既可以根据P值进行过滤也可以根据卡方值的大小进行过滤。
方差检验(过滤法)
方差检验
是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。
scikit-learn中的VarianceThreshold转换器可用来删除特征值的方差达不到最低标准的特征。
from sklearn.feature_selection import VarianceThreshold
vt = VarianceThreshold()
vt.fit(X)
vt.variances_
#array([0.68, 0.19, 3.1 , 0.58])
得到特征的方差后可以根据需要进行过滤,当然我们也可以直接进行过滤
VarianceThreshold(threshold = 3).fit_transform(X)
array([[1.4],
[1.4],
[1.3],
[1.5],
直接根据输入的阈值(threshold )进行过滤
F检验(过滤法)
F检验,又称ANOVA,方差齐性检验,是用来捕捉每个特征与标签之间的线性关系的过滤方法。它即可以做回归也可以做分类,因此包含feature_selection.f_classif(F检验分类)和feature_selection.f_regression(F检验回归)两个类。其中F检验分类用于标签是离散型变量的数据,而F检验回归用于标签是连续型变量的数据。
我们只以分类为例,说明一下。
F检验的本质是寻找两组数据之间的线性关系,其原假设是”数据不存在显著的线性关系“。它返回F值和p值两个统 计量。
from sklearn.feature_selection import f_classif
f_classif(X,y)
#(array([ 119.26, 49.16, 1180.16, 960.01]),
#array([1.67e-31, 4.49e-17, 2.86e-91, 4.17e-85]))
和卡方过滤一样,我们希望选取p值小于0.05或0.01的特征,这些特征与标签时显著线性相关的,而p值大于 0.05或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_regression
mutual_info_regression(X,y)
#array([0.47, 0.22, 1. , 1. ])
RFE(包装法)
递归消除特征法,是使用一个基模型来进行多伦训练,每轮训练后,消除若干个权值系数的特征,在基于新的特征集进行下一轮训练。
RFE是一种贪婪的优化算法,旨在找到性能最佳的特征子集。
它反复创建模型,并在每次迭代时保留最佳特征或剔除最差特征,
下一次迭代时,它会使用上一次建模中没有被选中的特征来构建下一个模型,直到所有特征都耗尽为止。然后,它根据自己保留或剔除特征的顺序来对所有特征进行排名,最终选出一个最佳子集。
包装法的效果是所有特征选择方法中最利于提升模型表现的,它可以使用很少的特征达到很优秀的效果。
除此之外,在特征数目相同时,包装法和嵌入法的效果能够匹敌,不过它比嵌入法算得更快,
虽然它的计算量也十分庞大,不适用于太大型的数据。但是,包装法任然是最高效的特征选择方法。
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
#定义模型
RF = RandomForestClassifier(n_estimators=10, random_state=1)
RFE = RFE(estimator= RF, n_features_to_select=2, step=50)#n_features_to_select选择特征个数
RFE.fit(X,y)
#RFE(estimator=RandomForestClassifier(n_estimators=10, random_state=1),n_features_to_select=2, step=50)
RFE.ranking_
#array([2, 2, 1, 1])
RFE.support_
#array([False, False, True, True])
```
RFE.ranking_:重要性排名矩阵,数值越小重要性越大,越不容易被删除
SelectFromModel(嵌入法)
SelectFromModel主要采用基于模型的特征选择法,常见的基于惩罚项的特征选择法和基于树模型的特征选择法。
第一种是基于L1的特征选择,使用L1正则化的线性模型会得到稀疏解,当目标是降低维度的时候,可以使用sklearn中的给予L1正则化的线性模型,比如LinearSVC,逻辑回归,或者Lasso。但是要注意的是:在 SVM 和逻辑回归中,参数 C 是用来控制稀疏性的:小的 C 会导致少的特征被选择。使用 Lasso,alpha 的值越大,越少的特征会被选择。
```python
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
selector = SelectFromModel(estimator=LogisticRegression( )).fit(X, y)
selector.get_support()
#array([False, False, True, True])
selector.transform(X)
array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2],
```
Tree类的算法包括决策树,随机森林等会在训练后,得出不同特征的重要程度,我们也可以利用这一重要属性对特征进行选择。
from sklearn.ensemble import GradientBoostingClassifier
selector = SelectFromModel(estimator=GradientBoostingClassifier( )).fit(X, y)
selector.get_support()
#array([False, False, True, True])
selector.transform(X)
array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2],
[1.7, 0.4],