机器学习 (四): 特征选择
机器学习 特征选择
本博客是 <Machine Learing With Python> 一书 chapter 10 的读书笔记
概述
特征选择即去掉对模型没有价值的特征, 根据手段不同可分为三类:
- filter: 字面意思是过滤, 原理是根据统计特征 (方差, 协方差, 等) 按照一定阈值或者排名直接选择特征; 这种方法比较简单, 就和过滤一样没什么技术含量.
- wrapper: 字面意思是封装, 原理是用你的模型不断尝试特征的各个子集, 直到找到一个特征最少且性能最好的子集; 我认为 wrapper 的意思就是说不像 filter 一样用一个简单的统计属性, 而是用一个复杂的函数 (即你的模型的封装) 来衡量特征的好坏.
- embedded: 有些学习算法, 如 AdaBoost 在训练过程中会自动修改各个特征的权重, embedded 方法即为将特征选择过程嵌入到模型训练过程中, 根据训练的结果再从中选择权重最大的几个特征 (由于本章中没有提及该方法的具体实现, 所以本博客也不会对该方法进行详细说明)
Filter 方法
根据方差
方差用来衡量一个随机变量的离散程度, 方差越小表示该变量越稳定, 一般认为 (但是我不赞成) 方差小的特征含的信息量较小
直接根据一个阈值来滤掉特征:
from sklearn.datasets import load_iris
from sklearn.feature_selection import VarianceThreshold
import numpy as np
data = load_iris().data
# 原本的特征数量
print('orig dim: ', data.shape[1])
# 每个特征的方差
print('var: ', data.var(axis=0))
# 以0.5为阈值过滤后的特征数量
print('new dim: ', VarianceThreshold(0.5).fit_transform(data).shape[1])
输出
orig dim: 4
var: [0.68112222 0.18871289 3.09550267 0.57713289]
new dim: 3
我们发现第二个特征方差最小.
但是, 因为方差的大小和数据的scale成平方关系, 所以在计算方差前应将特征缩放到同一取值范围
from sklearn.datasets import load_iris
from sklearn.preprocessing import maxabs_scale
import numpy as np
data = maxabs_scale(load_iris().data)
print('var: ', data.var(axis=0))
输出
var: [0.01091367 0.00974757 0.06501791 0.09234126]
我们发现缩放后四个特征的方差都差不多. 此时就很难找到一个好的阈值来进行过滤了.
我个人认为, 根据方差来选择特征是一个非常幼稚的想法, 特征本身的发散程度和target并没有相关性, 反而有时候恰恰是方差小的特征才是决定target的关键.
根据协方差
有些特征之间可能会彼此相关, 在统计上表现为二者之间的协方差很高, 此时需要去掉冗余的特征.
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
a = np.stack([np.arange(10), np.arange(10) // 2 * 2, np.random.rand(10)]).T
a = pd.DataFrame(a)
a = np.triu(a.corr().abs())
sns.heatmap(a)
我们发现特征0和特征1的协方差很高 (接近1), 因此可以去掉2或者1的其中之一.
根据
检验 (针对离散特征) 的逻辑就是对某一特征与样本标签进行独立性检验, 如果二者相互独立, 那么, 否则相关性与其值成正比.
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
SelectKBest(chi2, 2).fit_transform(load_iris().data, load_iris().target)
Wrapper 方法
RFECV
全称 Recursive Feature Elimination using Cross Validation
逻辑很简单, 即用你想要训练的模型, 先用全部特征训练, 然后逐步减少特征, 每次训练通过交叉验证的方式来打分, 从而可以得到一个特征最少, 得分最高的方案.
from sklearn.datasets import make_regression
from sklearn.feature_selection import RFECV
from sklearn import datasets, linear_model
# 创建一个用于线性回归的数据集, 其中有100个特征, 但只有两个是真正有用的
features, target = make_regression( n_samples = 1000,
n_features = 100,
n_informative = 2
)
model = linear_model.LinearRegression()
refcv = RFECV(estimator=model, step=1, scoring="neg_mean_squared_error", cv = 5)
refcv.fit(features, target)
refcv.transform(features)
print(refcv.n_features_)
输出
2
总结
特征选择这个工作是特征工程中最为重要的步骤, 但是这个步骤依靠的更多的是经验和深入挖掘, sklearn 提供的 feature_selection 库中的函数往往只能作为粗略的预处理步骤 (比如从上千个特征中选取一百个较为重要的出来), 更进一步的处理还需要依靠自己.
上一篇: Java基础 学习笔记9
推荐阅读
-
机器学习 (四): 特征选择
-
浅谈对于《机器学习》(周志华)第四章4.2.1信息增益与ID3决策树训练算法的个人理解
-
【机器学习】西瓜书_周志华,python实现基于信息熵进行划分选择的决策树算法
-
机器学习算法---决策树中用于特征选择的信息增益
-
机器学习速成课程 | 练习 | Google Development——编程练习:特征集
-
机器学习决策树算法中特征选项的算法实现——信息熵
-
机器学习速成课程 | 练习 | Google Development——编程练习:特征组合
-
《机器学习实战》《西瓜书》学习(四)-决策树
-
机器学习:决策树(四) —— sklearn决策树的使用及其可视化
-
机器学习——数据清洗,特征选择