Feature Selection 特征选择(一) SelectFromModel

特征选择
数据预处理完成之后,我们需要选择有意义的特征进入模型进行训练,通常来说,从两个方面考虑来选择特征:
1、特征是否发散,如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本没有差异,这个特征对于样本的区分并没有什么作用
2、特征与目标的相关性:
根据特征选择的形式可以分为以下3种:
1、filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者阈值的个数选择特征
2、wrapper:包装法:根据目标函数(通常是预测效果评分)每次选择若干特征,或者排除若干特征)
3、embedder:嵌入法:先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征,类似过滤法,但是是通过训练来确定特征的优劣
sklearn.feature_selection库来进行特征选择
一。filter
1.1、方差选择法:先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征

from sklearn.feature_selection import VarianceThreshold 
VarianceThreshold(threshold=3).fit_transform(iris.data)#threshold为方差的阈值,返回值是特征选择后的数据

1.2、相关系数法:先要计算各个特征对目标值的相关系数以及相关系数的P值

from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr
#选择K个最好的特征,返回选择特征后的数据
#第一个参数为计算评估特征是否好的函数,该函数输入特征举证和目标向量,输入二元组
(评分,P值)的数组,K为选择的特征的个数
SelectKBest(lambda X,Y:array(map(lambda x:pearsonr(x,Y),x,T)).T,k=2).fit_transform(iris.data,iris.target)

1.3、卡方检验
经典的卡方检验是检验定性自变量对定性因变量的相关性,假设自变量有B种取值,因变量有M种取值,假设自变量有N种取值,因变量有M种取值,考虑自变量=i,因变量等于j的样本的频数的观察值和期望的差距,构建统计量
在这里插入图片描述
这种统计量的含义简而言之就是自变量对因变量的相关性

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
SelectKBest(chi2,k=2).fit_transform(iris.data,iris.target)#选择K个最好的特征,返回选择特征后的数据

1.4、互信息法:

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)

有很多方法
第一种:是在数据预处理 期间进行变量之间的相关性 分析,利用热力图和业务的理解筛选
https://www.jianshu.com/p/aba5685c580a 有进行特征工程,filter 等各种筛选方法
第二种:利用机器学习
filter
特征工程多特征选择参考
https://blog.csdn.net/u012102306/article/details/52299427 里面有很多特征工程的方法
https://www.jianshu.com/p/b3056d10a20f
https://www.jianshu.com/p/f5f54a39cb19
https://www.cnblogs.com/jasonfreak/p/5448385.html

x = df_select.drop(['user_id','overdue'],axis=1)
x = np.array(x)
y = df_select[['overdue']]
y = np.array(y)

from sklearn.feature_selection import SelectKBest, f_classif
selector = SelectKBest(f_classif, k=5)
a=selector.fit(x,y)
print(np.array(a.scores_),'\n',a.get_support())

Wrapper法:
这里使用递归消除特征法,使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。使用feature_selection库的RFE类来选择特征

from sklearn.tree import DecisionTreeClassifier
from sklearn.feature_selection import RFE
model1 = DecisionTreeClassifier()
rfe = RFE(model1,5)
rfe = rfe.fit(x,y)
print(rfe.support_) 
print(rfe.ranking_)

二、wrapper:
2.1递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练

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)

三、embedded
3.1、基于惩罚项的特征选择法
使用带惩罚项的基模型,除了筛选特征外,同时也进行了降维,使用feature_selection库的SelectFromModel类结合带L1惩罚项的逻辑回归模型,来选择特征的代码如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择
SelectFromModel(LogisticRegression(penalty='l1',C=0)).fit_transform(iris.data,iris.target)
from sklearn.linear_model import LogisticRegression
 

L1惩罚项降维的原理在于保留多个对目标值具有同等相关性的特征中的一个,所以没选到的特征不代表不重要,可结合L2来优化,具体操作是:若一个特征在L1中的权值1,选择在L2中权值差别不大且在L1中权值为0的特征来构成同类集合,然后将这一集合中的特征评分L1中的权重,故需要构建一个逻辑回归模型


class LR(LogisticRegression):
    def __init__(self, threshold=0.01, dual=False, tol=1e-4, C=1.0,
                 fit_intercept=True, intercept_scaling=1, class_weight=None,
                 random_state=None, solver='liblinear', max_iter=100,
                 multi_class='ovr', verbose=0, warm_start=False, n_jobs=1):
 
        #权值相近的阈值
        self.threshold = threshold
        LogisticRegression.__init__(self, penalty='l1', dual=dual, tol=tol, C=C,
                 fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight=class_weight,
                 random_state=random_state, solver=solver, max_iter=max_iter,
                 multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
        #使用同样的参数创建L2逻辑回归
        self.l2 = LogisticRegression(penalty='l2', dual=dual, tol=tol, C=C, fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight = class_weight, random_state=random_state, solver=solver, max_iter=max_iter, multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
 
    def fit(self, X, y, sample_weight=None):
        #训练L1逻辑回归
        super(LR, self).fit(X, y, sample_weight=sample_weight)
        self.coef_old_ = self.coef_.copy()
        #训练L2逻辑回归
        self.l2.fit(X, y, sample_weight=sample_weight)
 
        cntOfRow, cntOfCol = self.coef_.shape
        #权值系数矩阵的行数对应目标值的种类数目
        for i in range(cntOfRow):
            for j in range(cntOfCol):
                coef = self.coef_[i][j]
                #L1逻辑回归的权值系数不为0
                if coef != 0:
                    idx = [j]
                    #对应在L2逻辑回归中的权值系数
                    coef1 = self.l2.coef_[i][j]
                    for k in range(cntOfCol):
                        coef2 = self.l2.coef_[i][k]
                        #在L2逻辑回归中,权值系数之差小于设定的阈值,且在L1中对应的权值为0
                        if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:
                            idx.append(k)
                    #计算这一类特征的权值系数均值
                    mean = coef / len(idx)
                    self.coef_[i][idx] = mean
        return self

使用feature_selection库的SelectFromModel类结合带L1以及L2惩罚项的逻辑回归模型,来选择特征的代码如下:

from sklearn.feature_selection import SelectFromModel
#带L1和L2惩罚项的逻辑回归作为基模型的特征选择
#参数threshold为权值系数之差的阈值
SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(iris.data, iris.target)

3、基于树模型的特征选择法:GBDT也可以作为基模型进行特征选择,使用代码如下

3.4 回顾
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data,iris.target)

在这里插入图片描述
四、降维
当特征选择完成后,就可以直接训练模型了,但是可可能有特征矩阵过大,导致计算量大,训练时间长的问题,降低维也是必不可少的,常见的降维方法有基于L1惩罚项的模型意外,还有主成分分析法PCA和线性判别式LDA,LDA本身也是一个分类模型,PCA LDA 有很多相似点,其本质是要将原始的样本映射到维度更低的样本空间中,但两者的映射目标不一样,PCA是为了让映射后的样本具有最大的发散性,LDA是为了让映射后的样本有最好的分类性能,PCA是一种无监督的姜维方法,LDA是一种有监督的降维方法

from sklearn.decomposition import PCA
PCA(n_components=2).fit_transform(iris.data)#n_components是主成分数目 

2、线性判别分析法LDA

from sklearn.lda import LDA
LDA(n_components=2).fit_transform(iris.data,iris.target)

在这里插入图片描述

筛选的结果为:
‘expen_avg’, ‘last_repay_diff’, ‘credit_amount’, ‘cur_bill_minrepay’, ‘brows_beh’
可以看出两个方法,除了特征expen_avg、cur_bill_minrepay,其他选择的特征都不同,且Wrapper法选择的都是连续型变量。
交叉验证:

一、sklearn.feature_selection.SelecFromModel:
fit后得到coef_ 或feature_importances_,应用于特征中,小于设定的阈值特征认为不重要,可去除。coef_(系数)适用于线性模型,而无系数的非线性模型使用feature_importances_ 。
SelectFromModel包括:L1-based feature selection 、 Tree-based feature selection 等

L1-based feature selection

from sklearn.feature_selection import SelectFromMldel
from sklearn.linear_model import Lasso#此处以L1正则化的线性模型lasso为例
lasso=Lasso()
lasso.fit(X,y)#训练模型,传入X、y, 数据中不能包含miss_value
model=SelectFromModel(lasso)
X_new=model.transform(X)# 此步可删除参数为0的特征,使用get_dummies处理后的数据需一个特征包含的所有项都为0
#Tree-based feature selection在无系数的非线性模型中,通过计算得到特征重要性,根据重要性筛选无关特征
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestRegressor		# 同样以此模型举例
rf = RandomForestRegressor()							# 默认参数
rf.fit(X, y)
model = SelectFromModel(rf)
X_new = model.transform(X)

SelectFromModel
sklearn在Feature selection模块中内置了一个SelectFromModel,该模型可以通过Model本身给出的指标对特征进行选择,其作用与其名字高度一致,select (feature) from model。
SelectFromModel 是一个通用转换器,其需要的Model只需要带有conef_或者feature_importances属性,那么就可以作为SelectFromModel的Model来使用. 如果相关的coef_ 或者 featureimportances 属性值低于预先设置的阈值,这些特征将会被认为不重要并且移除掉。除了指定数值上的阈值之外,还可以通过给定字符串参数来使用内置的启发式方法找到一个合适的阈值。可以使用的启发式方法有 mean 、 median 以及使用浮点数乘以这些(例如,0.1*mean )。

根据基础学习的不同,在estimator中有两种选择方式

第一种是基于L1的特征选择,使用L1正则化的线性模型会得到稀疏解,当目标是降低维度的时候,可以使用sklearn中的给予L1正则化的线性模型,比如LinearSVC,逻辑回归,或者Lasso。但是要注意的是:在 SVM 和逻辑回归中,参数 C 是用来控制稀疏性的:小的 C 会导致少的特征被选择。使用 Lasso,alpha 的值越大,越少的特征会被选择。

第二种是给予Tree的特征选择,Tree类的算法包括决策树,随机森林等会在训练后,得出不同特征的重要程度,我们也可以利用这一重要属性对特征进行选择。

但是无论选择哪一种学习器,我们都要记住的是我们的特征选择的最终标准应当是选择最好的特征,而非必须依照某种方法进行选择

几个重要的参数,属性,方法
threshold : 阈值,string, float, optional default None
可以使用:median 或者 mean 或者 1.25 * mean 这种格式。
如果使用参数惩罚设置为L1,则使用的阈值为1e-5,否则默认使用用mean
prefit :布尔,默认为False,是否为训练完的模型,(注意不能是cv,GridSearchCV或者clone the estimator得到的),如果是False的话则先fit,再transform。

threshold_ :采用的阈值

简单的示例:
使用L1进行特征选择
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel

Load the boston dataset.

load_iris = load_iris()
X, y = load_iris[‘data’], load_iris[‘target’]
print(“X 共有 %s 个特征”%X.shape[1])

lsvc = LinearSVC(C=0.01, penalty=“l1”, dual=False).fit(X, y)
model = SelectFromModel(lsvc,prefit=True)
X_new = model.transform(X)
print(“X_new 共有 %s 个特征”%X_new.shape[1])
1
2
3
4
5
6
7
8
9
10
11
12
13
X 共有 4 个特征
X_new 共有 3 个特征
1
2
基于树的特征选择
from sklearn.ensemble import ExtraTreesClassifier
clf = ExtraTreesClassifier().fit(X,y)
print(“clf.feature_importances_ :”,clf.feature_importances_)

model_2 = SelectFromModel(clf,prefit=True)
X_new_2 = model_2.transform(X)
print(“X_new_2 共有 %s 个特征”%X_new_2.shape[1])

model_3 = SelectFromModel(clf,prefit=True,threshold=0.15)
X_new_3 = model_3.transform(X)
print(“model的阈值为 :%s”%model_3.threshold)
print(“X_new_3 共有 %s 个特征”%X_new_3.shape[1])
1
2
3
4
5
6
7
8
9
10
11
12
clf.feature_importances_ : [0.14016636 0.06062787 0.47708914 0.32211664]
X_new_2 共有 2 个特征
model的阈值为 :0.15
X_new_3 共有 2 个特征
1
2
3
4
更多的示例
特征的选取并不一定代表着性能的提升,这一点在所有的特征选择中是一致的
我对sklearn中的例子(Feature selection using SelectFromModel and LassoCV),稍加改造,就可以一见分毫

import matplotlib.pyplot as plt
import numpy as np

from sklearn.datasets import load_boston
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LassoCV

Load the boston dataset.

boston = load_boston()
X, y = boston[‘data’], boston[‘target’]

We use the base estimator LassoCV since the L1 norm promotes sparsity of features.

clf = LassoCV()

Set a minimum threshold of 0.25

sfm = SelectFromModel(clf, threshold=0.0)
sfm.fit(X, y)
n_features = sfm.transform(X).shape[1]

def GetCVScore(estimator,X,y):
from sklearn.model_selection import cross_val_score
nested_score = cross_val_score(clf, X=X, y=y, cv=5)
nested_score_mean = nested_score.mean()
return nested_score_mean

Reset the threshold till the number of features equals two.

Note that the attribute can be set directly instead of repeatedly

fitting the metatransformer.

nested_scores = []
n_features_list = []
while n_features > 2:
sfm.threshold += 0.01
X_transform = sfm.transform(X)
n_features = X_transform.shape[1]

nested_score = GetCVScore(estimator=clf, X=X_transform, y=y)
nested_scores.append(nested_score)
n_features_list.append(n_features)
# print("nested_score: %s"%nested_score)
# print("n_features: %s"%n_features)
# print("threshold: %s"%sfm.threshold)

Plot the selected two features from X.

plt.title(
"Features selected from Boston using SelectFromModel with "
“threshold %0.3f.” % sfm.threshold)
feature1 = X_transform[:, 0]
feature2 = X_transform[:, 1]
plt.plot(feature1, feature2, ‘r.’)
plt.xlabel(“Feature number 1”)
plt.ylabel(“Feature number 2”)
plt.ylim([np.min(feature2), np.max(feature2)])
plt.show()

plt.scatter(n_features_list,nested_scores,c=u’b’,marker=u’.’,label = ‘Selected’)
plt.scatter(X.shape[1],GetCVScore(estimator=clf, X=X, y=y),c=u’r’,marker=u’*’,label = ‘old feature’)
plt.title(“The reduction of features does not necessarily bring up the performance of the model”)
plt.xlabel(“number of features”)
plt.ylabel(“score of model”)
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

前面的第一个例子,展示了如何同时使用selectFromModel and Lasso,而后面我所添加的内容,则展示了:The reduction of features does not necessarily bring up the performance of the model

特征选取并不一定升:所有特征有效的情况下,去除的特征只能带来模型性能的下降,即使不是全部有效很多时候,低重要程度的特征也并不一定代表着一定会导致模型性能的下降,因为某种度量方式并不代表着该特征的最终效果,很多时候我们的度量方式,往往只是一个参考而已.

  • 7
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值