一、特征选择的原因:
1、冗余:部分特征相关度太高,消耗计算性能,影响决策树分支的选择。
2、噪声:部分特征是对预测结果有负影响
3、降维:减少特征数量、降维,使模型泛化能力更强,减少过拟合
4、特征选择与降维的关系:特征选择只筛选掉原本特征里和结果预测关系不大的,后者做特征的计算组合构成新特征。SVD、PCA降维也能解决一定的高纬度问题。
二、特征选择的方法:
1、过滤型(Filter):
(1)评估单个特征与结果值之间的相关程度,排序留下TopN相关的特征部分
(2)缺点:没有考虑到特征之间的关联作用,可能把有用的关联特征误踢掉。
(3)方法:
- 移除低方差的特征 (Removing features with low variance)
假设某特征的特征值只有0和1,并且在所有输入样本中,95%的实例的该特征取值都是1,那就可以认为这个特征作用不大。如果100%都是1,那这个特征就没意义了。当特征值都是离散型变量的时候这种方法才能用,如果是连续型变量,就需要将连续变量离散化之后才能用。而且实际当中,一般不太会有95%以上都取某个值的特征存在,所以这种方法虽然简单但是不太好用。可以把它作为特征选择的预处理,先去掉那些取值变化小的特征,然后再从接下来提到的的特征选择方法中选择合适的进行进一步的特征选择。
X = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]]
selector = VarianceThreshold(threshold=(.8 * (1 - .8))) #参数threshold为方差的阈值
selector.fit_transform(X)
>>>array([[2, 0],
[1, 4],
[1, 1]])
- 单变量特征选择 (Univariate feature selection)
单变量特征选择的原理是分别单独的计算每个变量的某个统计指标,根据该指标来判断哪些变量重要,剔除那些不重要的变量。这种方法比较简单,易于运行,易于理解,通常对于理解数据有较好的效果(但对特征优化、提高泛化能力来说不一定有效)。
(1)分类问题(y离散),可采用:
- 卡方检验
- f_classif
- mutual_info_classif
- 互信息
(2)对于回归问题(y连续),可采用:
- 皮尔森相关系数
- f_regression,
- mutual_info_regression
- 最大信息系数
(3)特征选择方式
- SelectKBest 移除得分前 k 名以外的所有特征(取top k)
- SelectPercentile 移除得分在用户指定百分比以后的特征(取top k%)
- 对每个特征使用通用的单变量统计检验: 假正率(false positive rate) SelectFpr, 伪发现率(false discovery rate) SelectFdr, 或族系误差率 SelectFwe.
- GenericUnivariateSelect 可以设置不同的策略来进行单变量特征选择。同时不同的选择策略也能够使用超参数寻优,从而让我们找到最佳的单变量特征选择策略。
(4)例子
卡方(Chi2)检验:经典的卡方检验是检验定性自变量对定性因变量的相关性。比如,我们可以对样本进行一次chi2 测试来选择最佳的两项特征:
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
iris = load_iris()
X, y = iris.data, iris.target
print(X.shape)
X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
print(X_new.shape)
>>>(150, 4)
>>>(150, 2)
Pearson相关系数 (Pearson Correlation):皮尔森相关系数是一种最简单的,能帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为[-1,1],-1表示完全的负相关,+1表示完全的正相关,0表示没有线性相关。
import numpy as np
from scipy.stats import pearsonr
np.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
# pearsonr(x, y)的输入为特征矩阵和目标向量,能够同时计算 相关系数 和p-value.
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))
>>>Lower noise (0.7182483686213841, 7.32401731299835e-49)
>>>Higher noise (0.057964292079338155, 0.3170099388532475)
2、包裹型(Wrapper)
- 递归特征消除法(Recursive Feature Elimination):使用一个基模型来进行多轮训练,每轮训练后,移除若干权值系数的特征,再基于新的特征集进行下一轮训练。对特征含有权重的预测模型(例如,线性模型对应参数coefficients),RFE通过递归减少考察的特征集规模来选择特征。如线性回归:(1)在全量特征跑一个模型。(2)根据线性模型的系数(体现相关性)。删除5-10%的弱特征,观察准确率/auc的变化。(3)准确率/auc逐步进行,知道出现大的下滑停止。
- RFECV 通过交叉验证的方式执行RFE,以此来选择最佳数量的特征:对于一个数量为d的feature的集合,他的所有的子集的个数是2的d次方减1(包含空集)。指定一个外部的学习算法,比如SVM之类的。通过该算法计算所有子集的validation error。选择error最小的那个子集作为所挑选的特征。
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
rf = RandomForestClassifier()
iris=load_iris()
X,y=iris.data,iris.target
rfe = RFE(estimator=rf, n_features_to_select=3)
X_rfe = rfe.fit_transform(X,y)
X_rfe.shape
>>>(150, 3)
3、嵌入型(Embedded)
- 根据模型本身来分析特征的重要性(有别于包裹式,从生成的模型权重进行特征选择)。
- 最常见的方法为使用正则化方法来做特征选择
- 举个例子,早期电商用LR做CTR预估,在3-5亿维的系数特征上用L1正则化的LR模型。剩余2-3千万的特征,意味着其他的特征重要度不够。
(1)基于L1的特征选择 (L1-based feature selection):
- 使用L1范数作为惩罚项的线性模型(Linear models)会得到稀疏解:大部分特征对应的系数为0。当你希望减少特征的维度以用于其它分类器时,可以通过 feature_selection.SelectFromModel 来选择不为0的系数。
- 常用于此目的的稀疏预测模型有 linear_model.Lasso(回归), linear_model.LogisticRegression 和 svm.LinearSVC(分类)
from sklearn.feature_selection import SelectFromModel
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
iris=load_iris()
X,y=iris.data,iris.target
lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X,y)
model = SelectFromModel(lsvc, prefit=True)
X_embed = model.transform(X)
X_embed.shape
4、工作中常用到的模型选择方法
(1)变量重要性
- IV值:IV其实就是在WOE前面加上一项。
最后只需要将每一个区间的iv加起来就得到总的iv值: - 卡方检验
- 模型筛选:集成模型输出特征重要性
(2)共线性
- 相关系数 COR:单独看两个变量的时候我们会使用皮尔逊相关系数
- 方差膨胀系数 VIF:在多元回归中,我们可以通过计算方差膨胀系数VIF来检验回归模型是否存在严重的多重共线性问题
其中,为自变量 对其余自变量作回归分析的负相关系数。方差膨胀系数是容忍度的倒数。
方差膨胀系数VIF越大,说明自变量之间存在共线性的可能性越大。一般来讲,如果方差膨胀因子超过10,则回归模型存在严重的多重共线性。又根据Hair(1995)的共线性诊断标准,当自变量的容忍度大于0.1,方差膨胀系数小于10的范围是可以接受的,表明白变量之间没有共线性问题存在。