机器学习的特征选择方法

时间:2024-04-09 13:46:23

有时候特征太多了也是一个问题,容易过拟合。为了降低模型的复杂程度,降低过拟合的可能性,我们会减少需要的学习的特征。

特征选择法主要有三种,分别是过滤法,包裹法和嵌入法。

1.过滤法

这种方法主要是基于统计检验,根据特征之间的关系去掉具有线性相关的特征,还有根据特征和标签的关系,筛选关系大的特征。

这种方法的好处是具有通用性,不管什么算法都可以这么用。但是问题是这种方法没有考虑算法的特殊性,可能某些算法就是喜欢那些不起眼的特征,有这些特征,它的表现就更好。

简单介绍几种过滤法。

(1).方差阈值法

这种方法就是计算各个特征的方差,然后把方差过低的特征删除,为什么用这个办法?因为如果一个特征全都是一个数值,说明它对分类毫无意义,而这样的特征方差为0,当然这是一种极端情况,但是特征毫无波动,那它确实没什么用。sklearn提供了VarianceThreshold这个方法;

(2).假设检验法

这种一般是使用假设检验进行特征选择,消灭掉P值大于0.05的特征,这种教条主义的P值实际上经常帮倒忙,但是偶尔也会有不错的结果。

sklearn提供了卡方检验chi2,f检验r_regression等等,这些可以结合SelectFpr,SelectFdr,SelectFwe等方法使用

(3).特征相关性

删掉线性相关的特征,我觉得这个方法包含很多种,比如特征之间的互信息,皮尔逊相关系数等等

(4).Fish得分

这种方法有点类似LDA的思想,某一类的特征可能更集中,而不属于这个类的特征就要离得远一些。

还有一些方法,不仅上面提到的。可以再训练分类器之前就进行特征选择的方法,都属于过滤法。

2.包裹法

前向选择,后向选择,分支界定法,递归特征选择法都属于嵌入法,这种方法和特定的算法有一定的交互性。

sklearn提供了递归特征选择法RFE,RFECV,还有前向或者后向选择SequentialFeatureSelector,RFECV是RFE的交叉检验版本,SequentialFeatureSelector可以选择是使用前向还是后向选择,缺点是它居然没有记录每一次的评分。RFE必须带有特征重要性评分的分类器使用,对于基于高斯内核的支持向量机救没办法用了,而具有评分的分类器有树类型的分类器,线性回归等等。

所谓评分就是各个特征的重要评分,比如线性回归的参数就代表了各个特征的重要性,决策树再分裂节点的时候使用的特征具有的信息增益大小等等,具有这些的分类器才能使用RFE,但是SequentialFeatureSelector不用。

from mlxtend.feature_selection import SequentialFeatureSelector
from mlxtend.plotting import plot_sequential_feature_selection
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

#自定义一个评价函数,sklearn是按照分数越高越好来选特征的,所以我们取个负数
#FPR+FNR最大值为2
def score_fpr_fnr(model, X, y):
    y_pred = model.predict(X)
    mat = confusion_matrix(y, y_pred)
    fpr = mat[0,1]/(mat[0,0]+mat[0,1])#假正类率,错误识别的负类除以整个负类
    fnr = mat[1,0]/(mat[1,1] + mat[1,0])#假负类率
    return 2 - fpr - fnr

#加载数据集二分类
data = load_breast_cancer()
dataset = data['data']
label = data['target']
#划分数据集
X_train, X_test, y_train, y_test = train_test_split(dataset, label, test_size=0.2, shuffle=42)

model = RandomForestClassifier()
val_score_list = []#记录每一次的交叉检验均值分数
test_score_list = []#记录每一次测试的分数
#每次要求的后向选择特征数量
for feature_number in range(1, X_train.shape[1]+1):
    #不进行交叉验证,因为要算太久了,可以根据情况设置,设置自定义的评价方法
    sfs = SequentialFeatureSelector(model, k_features=feature_number, forward=True,scoring=score_fpr_fnr, cv=None)
    sfs.fit(X_train, y_train)
    #训练分类器然后测试
    X_train_transform = sfs.transform(X_train)
    X_test_transform = sfs.transform(X_test)
    model.fit(X_train_transform , y_train)
    my_score= score_fpr_fnr(model,X_test_transform,y_test)#每一次选择特征的分数
    #因为制作了一次交叉检验,所以是1,如果多次,就要循环取得
    f_score = sfs.subsets_[1]['avg_score']
    val_score_list .append(f_score)
    test_score_list.append(my_score)

3.嵌入法

这种算法不具有迁移性,因为它与算法本身相关,比如线性回归算法,它的参数w代表了每一个特征的重要性,但是这种w无法用到决策树上面,由于这种方法是算法本身的一种性质,所以就是嵌入在算法内部的意思,因而叫嵌入法。

4.混合

以上三种方法可以进行混合使用,比如使用嵌入法对特征重要性排序,然后使用包裹法进行特征选择。

以后有空回来补充其他的代码