作者:jliang

https://blog.csdn.net/jliang3

 

1.特征选择介绍

1)特征分类

  • 相关特征:对于学习任务(例如分类问题)有帮助,可以提升学习算法的效果;
  • 无关特征:对于我们的算法没有任何帮助,不会给算法的效果带来任何提升;
  • 冗余特征:不会对我们的算法带来新的信息,或者这种特征的信息可以由其他的特征推断出;

2)特征选择的目的

对于一个特定的学习算法来说,哪一个特征是有效的是未知的。因此,需要从所有特征中选择出对于学习算法有益的相关特征。而且在实际应用中,经常会出现维度灾难问题。如果只选择所有特征中的部分特征构建模型,那么可以大大减少学习算法的运行时间,也可以增加模型的可解释性。

  • 减少特征数量、降维
  • 降低学习任务的难度,提升模型的效率
  • 使模型泛华能力更强,减少过拟合
  • 增强对特征和特征值之间的理解

3)特征选择的原则

获取尽可能小的特征子集,不显著降低分类精度、不影响分类分布以及特征子集应具有稳定、适应性强等特点。

2.特征选择的方法

1)Filter方法(过滤式)

(1)主要思想是:对每一维特征“打分”,即给每一维的特征赋予权重,这样的权重就代表着该特征的重要性,然后依据权重排序。

(2)先进行特征选择,然后去训练学习器,所以特征选择的过程与学习器无关。相当于先对特征进行过滤操作,然后用特征子集来训练分类器。

(3)主要方法

  • Chi-squared test(卡方检验)
  • Information gain(信息增益)
  • Correlation coefficient scores(相关系数)

2)Wrapper方法(包裹式)

(1)主要思想是:将子集的选择看作是一个搜索寻优问题,生成不同的组合,对组合进行评价,再与其他的组合进行比较。这样就将子集的选择看作是一个优化问题,这里有很多的优化算法可以解决,尤其是一些启发式的优化算法,如GA、PSO(如:优化算法-粒子群算法)、DE、ABC(如:优化算法-人工蜂群算法)等,

(2)直接把最后要使用的分类器作为特征选择的评价函数,对于特定的分类器选择最优的特征子集。

(3)主要方法有:递归特征消除算法

3)Embedded方法(嵌入式)

(1)主要思想是:在模型既定的情况下学习出对提高模型准确性最好的特征。也就是在确定模型的过程中,挑选出那些对模型的训练有重要意义的特征。

(2)简单易学的机器学习算法--岭回归(Ridge Regression),就是线性回归过程加入了L2正则项。

3.方法一:去掉取值变化小的特征(Removing features with low variance

1)该方法一般用在特征选择前作为一个预处理的工作,即先去掉取值变化小的特征,然后再使用其他特征选择方法选择特征。

2)考察某个特征下,样本的方差值,可以认为给定一个阈值,抛弃哪些小于某个阈值的特征。

3)例子

(1)离散型变量:假设某特征的特征值只有0和1,并且在所有输入样本中,95%的实例的该特征取值都是1,那就可以认为这个特征作用不大。如果100%都是1,那这个特征就没意义了。

(2)连续型变量:需要将连续变量离散化之后才能用。

(3)而且实际当中,一般不太会有95%以上都取某个值的特征存在,所以这种方法虽然简单但是不太好用。可以把它作为特征选择的预处理,先去掉那些取值变化小的特征,然后再从接下来提到的的特征选择方法中选择合适的进行进一步的特征选择。

4)实现例子

from sklearn.feature_selection import VarianceThreshold

X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]

sel = VarianceThreshold(threshold=(.8 * (1 - .8)))

sel.fit_transform(X)

#array([[0, 1],

       [1, 0],

       [0, 0],

       [1, 1],

       [1, 0],

       [1, 1]])

4. 方法二:单变量特征选择(Univariate feature selection

  • 单变量特征选择方法独立的衡量每个特征与响应变量之间的关系,单变量特征选择能够对每一个特征进行测试,衡量该特征和响应变量之间的关系,根据得分扔掉不好的特征。对于回归和分类问题可以采用卡方检验等方式对特征进行测试。
  • 方法简单,易于运行,易于理解,通常对于理解数据有较好的效果(但对特征优化、提高泛化能力来说不一定有效);这种方法有许多改进的版本、变种。

1)Pearson相关系数(Pearson Correlation)

皮尔森相关系数是一种最简单的,能帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为[-1,1],-1表示完全的负相关(这个变量下降,那个就会上升),+1表示完全的正相关,0表示没有线性相关。

2)互信息和最大信息系数(Mutual information and maximal information coefficient)

以上就是经典的互信息公式了。想把互信息直接用于特征选择其实不是太方便:

(1)它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;

(2)对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。

3)距离相关系数(Distance correlation)

(1)距离相关系数是为了克服Pearson相关系数的弱点而生的。

(2)Pearson相关系数是0,我们也不能断定这两个变量是独立的(有可能是非线性相关)。

(3)但如果距离相关系数是0,那么我们就可以说这两个变量是独立的。

4)基于学习模型的特征排序(Model based ranking)

(1)这种方法的思路是直接使用你要用的机器学习算法,针对每个单独的特征和响应变量建立预测模型。

(2)其实Pearson相关系数等价于线性回归里的标准化回归系数。假如某个特征和响应变量之间的关系是非线性的,可以用基于树的方法(决策树、随机森林)、或者扩展的线性模型等。基于树的方法比较易于使用,因为他们对非线性关系的建模比较好,并且不需要太多的调试。但要注意过拟合问题,因此树的深度最好不要太大,再就是运用交叉验证。

5)卡方检验

(1)卡方检验属于简单易计算的Feature weight algorithm

(2)卡方检验是概率论和数理统计中常用的假设检验的思想,通过观察实际值和理论值的偏差来确定原假设是否成立。

  • 假设两个变量是独立的(此为原假设)
  • 然后观察实际值和理论值之间的偏差程度,若偏差足够小,则认为偏差是自然的样本误差,接受假设。
  • 若偏差大到一定程度,则否认原假设,接受备择假设。

6)程序实现

(1)sklearn.feature_selection.SelectKBest:返回k个最佳特征

(2)sklearn.feature_selection.SelectPercentile:返回表现最佳的前r%个特征

(3)例子:使用卡方检验选择特征

#导入sklearn库中的SelectKBest和chi2

from sklearn.feature_selection import SelectKBest ,chi2

#选择相关性最高的前5个特征

X_chi2 = SelectKBest(chi2, k=5).fit_transform(X, y)

X_chi2.shape

输出:(27, 5)

(4)其它可选的方法

  • f_classif: ANOVA F-value between label/feature for classification tasks.
  • mutual_info_classif: Mutual information for a discrete target.
  • chi2: Chi-squared stats of non-negative features for classification tasks.
  • f_regression: F-value between label/feature for regression tasks.
  • mutual_info_regression: Mutual information for a continuous target.
  • SelectPercentile: Select features based on percentile of the highest scores.
  • SelectFpr: Select features based on a false positive rate test.
  • SelectFdr: Select features based on an estimated false discovery rate.
  • SelectFwe: Select features based on family-wise error rate.
  • GenericUnivariateSelect: Univariate feature selector with configurable mode.

5. 方法三:线性模型和正则化

1)另一种主流的特征选择方法是基于机器学习模型的方法

(1)有些机器学习方法本身就具有对特征进行打分的机制,或者很容易将其运用到特征选择任务中,例如回归模型,SVM,决策树,随机森林等等。

(2)正则化模型

  • 正则化就是把额外的约束或者惩罚项加到已有模型(损失函数)上,以防止过拟合并提高泛化能力。
  • 损失函数由原来的E(X,Y)变为E(X,Y)+alpha||w||,w是模型系数组成的向量(有些地方也叫参数parameter,coefficients),||·||一般是L1或者L2范数,alpha是一个可调的参数,控制着正则化的强度。
  • 当用在线性模型上时,L1正则化和L2正则化也称为Lasso和Ridge。

2)L1正则化/Lasso regression

(1)L1正则化将系数w的l1范数作为惩罚项加到损失函数上,由于正则项非零,这就迫使那些弱的特征所对应的系数变成0。

(2)因此L1正则化往往会使学到的模型很稀疏(系数w经常为0),这个特性使得L1正则化成为一种很好的特征选择方法。

3)L2正则化/Ridge regression

(1)L2正则化将系数向量的L2范数添加到了损失函数中。

  •  由于L2惩罚项中系数是二次方的,这使得L2和L1有着诸多差异,最明显的一点就是,L2正则化会让系数的取值变得平均。
  • 对于关联特征,这意味着他们能够获得更相近的对应系数。
    • 可以看出,系数之和为常数时,各系数相等时惩罚是最小的,所以才有了L2会让各个系数趋于相同的特点。 
    • 但是对于L2来说,第一个模型的惩罚项是2alpha,但第二个模型的是4*alpha。
    • 如果用L1正则化,不论学到的模型是Y=X1+X2还是Y=2X1,惩罚都是一样的,都是2alpha。
    • 以Y=X1+X2为例,假设X1和X2具有很强的关联

(2)L2正则化对于特征选择来说一种稳定的模型,不像L1正则化那样,系数会因为细微的数据变化而波动。所以L2正则化和L1正则化提供的价值是不同的,L2正则化对于特征理解来说更加有用:表示能力强的特征对应的系数是非零。

4)程序实现

(1)多元线性回归,具有n个特征值

  • 预测公式如下y(i)=θ0+θ1x1(i)+θ2x2(i)+…++θnxni=Xb
  • 多元线性回归方程演变成求θ
  • sklearn中 中LinearRegression的fit()方法就是通过训练集求出θ,LinearRegression的两个属性intercept_和coef_分别对应θ0θ1-θn

(2)获取模型参数代码

if __name__ == '__main__':

    #获取boston数据

    boston=datasets.load_boston()

    x=boston.data

    y=boston.target

    #过滤掉异常值

    x=x[y<50]

    y=y[y<50]

    reg=LinearRegression()

    reg.fit(x,y)

    #求排序后的coef

    coefSort=reg.coef_.argsort()

    #featureNameSort: 按对标记值的影响,从小到大的各特征值名称

    #featureCoefSore:按对标记值的影响,从小到大的coef_

    featureNameSort=boston.feature_names[coefSort]

    featureCoefSore=reg.coef_[coefSort]

    print("featureNameSort:", featureNameSort)

    print("featureCoefSore:",featureCoefSore)

  运行代码,输出结果为:

featureNameSort: ['NOX' 'DIS' 'PTRATIO' 'LSTAT' 'CRIM' 'INDUS' 'AGE' 'TAX' 'B' 'ZN' 'RAD'  'CHAS' 'RM']

featureCoefSore: [-1.24268073e+01 -1.21088069e+00 -8.38888137e-01 -3.50952134e-01

 -1.05574295e-01 -4.35179251e-02 -2.36116881e-02 -1.37702943e-02 7.93577159e-03 

3.52748549e-02  2.50740082e-01  4.55405227e-01 3.75411229e+00]

  (3)从输出结果可以看出

  •   正相关影响系数最大的特征值是"RM":房间的平均数量,系数值为3.75;
  •   负相关影响系数最大的特征值是"NOX":一氧化氮浓度,系数值为-1.24;

6. 方法四:随机森林

随机森林具有准确率高、鲁棒性好、易于使用等优点,这使得它成为了目前最流行的机器学习算法之一。随机森林提供了两种特征选择的方法:mean decrease impurity和mean decrease accuracy。

1)平均不纯度减少(Mean decrease impurity)

(1)随机森林由多个决策树构成。决策树中的每一个节点都是关于某个特征的条件,为的是将数据集按照不同的响应变量一分为二。

(2)利用不纯度可以确定节点(最优条件),对于分类问题,通常采用基尼不纯度或者信息增益,对于回归问题,通常采用的是方差或者最小二乘拟合。

(3)当训练决策树的时候,可以计算出每个特征减少了多少树的不纯度。对于一个决策树森林来说,可以算出每个特征平均减少了多少不纯度,并把它平均减少的不纯度作为特征选择的值。

(4)程序实现:直接使用sklearn训练RF模型,然后通过feature_importances_属性可以得到每个特征的特征重要性,该特征重要性是根据不纯度减少计算而来。

2)平均精确度减少(Mean decrease accuracy)

(1)另一种常用的特征选择方法就是直接度量每个特征对模型精确率的影响。

(2)主要思路是打乱每个特征的特征值顺序,并且度量顺序变动对模型的精确率的影响。很明显,对于不重要的变量来说,打乱顺序对模型的精确率影响不会太大,但是对于重要的变量来说,打乱顺序就会降低模型的精确率。

(3)程序实现例子

from sklearn.cross_validation import ShuffleSplit

from sklearn.metrics import r2_score

from collections import defaultdict

X = boston["data"]

Y = boston["target"]

rf = RandomForestRegressor()

scores = defaultdict(list)

#crossvalidate the scores on a number of different random splits of the data

for train_idx, test_idx in ShuffleSplit(len(X), 100, .3):

    X_train, X_test = X[train_idx], X[test_idx]

    Y_train, Y_test = Y[train_idx], Y[test_idx]

    r = rf.fit(X_train, Y_train)

acc = r2_score(Y_test, rf.predict(X_test))

# 遍历特征的每一列

    for i in range(X.shape[1]):

        X_t = X_test.copy()

        # 对这一列特征进行混洗,交互了一列特征内部的值的顺序

        np.random.shuffle(X_t[:, i])

        shuff_acc = r2_score(Y_test, rf.predict(X_t))

        scores[names[i]].append((acc-shuff_acc)/acc)

print "Features sorted by their score:"

print sorted([(round(np.mean(score), 4), feat) for feat, score in scores.items()], reverse=True)

7. 方法五:顶层特征选择算法

之所以叫做顶层,是因为他们都是建立在基于模型的特征选择方法基础之上的,例如回归和SVM,在不同的子集上建立模型,然后汇总最终确定特征得分。

1)稳定性选择(Stability selection)

(1)稳定性选择是一种基于二次抽样和选择算法相结合较新的方法,选择算法可以是回归、SVM或其他类似的方法。

(2)它的主要思想是在不同的数据子集和特征子集上运行特征选择算法,不断的重复,最终汇总特征选择结果。

  • 比如可以统计某个特征被认为是重要特征的频率(被选为重要特征的次数除以它所在的子集被测试的次数)。

(3)理想情况下,重要特征的得分会接近100%。稍微弱一点的特征得分会是非0的数,而最无用的特征得分将会接近于0。

(4)程序实现例子

from sklearn.linear_model import RandomizedLasso

from sklearn.datasets import load_boston

boston = load_boston()

#using the Boston housing data.

#Data gets scaled automatically by sklearn's implementation

X = boston["data"]

Y = boston["target"]

names = boston["feature_names"]

rlasso = RandomizedLasso(alpha=0.025)

rlasso.fit(X, Y)

print("Features sorted by their score:")

print(sorted(zip(map(lambda x: round(x, 4), rlasso.scores_), names), reverse=True))

2)递归特征消除(Recursive feature elimination,RFE)

(1)递归特征消除的主要思想是反复的构建模型(如SVM或者回归模型)然后选出最好的(或者最差的)的特征(可以根据系数来选),把选出来的特征放到一遍,然后在剩余的特征上重复这个过程,直到所有特征都遍历了。

(2)这个过程中特征被消除的次序就是特征的排序。因此,这是一种寻找最优特征子集的贪心算法。

(3)RFE的稳定性很大程度上取决于在迭代的时候底层用哪种模型。

  • 例如,假如RFE采用的普通的回归,没有经过正则化的回归是不稳定的,那么RFE就是不稳定的;
  • 假如采用的是Ridge,而用Ridge正则化的回归是稳定的,那么RFE就是稳定的。

(4)程序实现例子

from sklearn.feature_selection import RFE

from sklearn.linear_model import LinearRegression

boston = load_boston()

X = boston["data"]

Y = boston["target"]

names = boston["feature_names"]

#use linear regression as the model

lr = LinearRegression()

#rank all features, i.e continue the elimination until the last one

rfe = RFE(lr, n_features_to_select=1)

rfe.fit(X,Y)

print("Features sorted by their rank:")

print(sorted(zip(map(lambda x: round(x, 4), rfe.ranking_), names)))

结果输出

Features sorted by their rank:

[(1, 'NOX'), (2, 'RM'), (3, 'CHAS'), (4, 'PTRATIO'), (5, 'DIS'), (6, 'LSTAT'), (7, 'RAD'), (8, 'CRIM'), (9, 'INDUS'), (10, 'ZN'), (11, 'TAX'), (12, 'B'), (13, 'AGE')]

参考文献 

[1]. 机器学习之特征选择. https://www.cnblogs.com/nolonely/p/6435083.html

[2]. 特征选择--scikit-learn. https://blog.csdn.net/a1368783069/article/details/52048349

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐