【数据挖掘】特征选择

本篇博文主要想谈一谈特征选择

特征选择是什么

在数据挖掘中,特征选择是指从给定的特征集合中选择出相关特征子集(或者剔除无关特征)的过程

为什么要使用特征选择

  1. 简化模型,使之更易于被研究人员或用户理解
  2. 缩短训练时间
  3. 改善通用性、降低过拟合的可能性(即降低方差)

特征选择的方法

将特征子集搜索机制与子集评价机制相结合,即可得到特征选择方法。常见的特征选择方法大致可以分为三类:过滤式(Filter)、包裹式(Wrapper)和嵌入式(Embedding)

1. 过滤式(Filter)

过滤式方法指,通过某种评价指标计算每一维特征的重要性,基于重要性分数对特征集合进行特征选择,然后再训练学习器,特征选择过程与后续学习器无关。这相当于先用特征选择对初始特征进行“过滤”,再用过滤后的特征来训练模型。

衡量每一维特征重要性的评价指标主要从两个方面来考虑:

  1. 特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
  2. 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。除方差法外,本文介绍的其他方法均从相关性考虑。

a. 方差

先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。使用 feature_selection 库的 VarianceThreshold 类来选择特征的代码如下:

1
2
3
4
5
from sklearn.feature_selection import VarianceThreshold

# 参数 threshold 为方差的阈值
# 返回值为特征选择后的数据
VarianceThreshold(threshold=3).fit_transform(iris.data)

b. 相关系数

先要计算各个特征对目标的相关系数以及相关系数的 P 值。用 feature_selection 库的 SelectKBest 类结合相关系数来选择特征的代码如下:

1
2
3
4
5
6
7
from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr

# 第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组 (评分,P值) 的数组,数组第 i 项为第 i 个特征的评分和 P 值。在此定义为计算相关系数
# 第二个参数 k 为选择的特征个数
# 返回值为特征选择后的数据
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)

c. 卡方检验

假设自变量有 N 种取值,因变量有 M 种取值,考虑自变量等于 i 且因变量等于 j 的样本频数的观察值与期望的差距,构建统计量:

$${\chi}^2 = \sum \frac{(A - E)^2}{E}$$

简而言之,该统计量的含义指自变量对因变量的相关性。用 feature_selection 库的 SelectKBest 类结合卡方检验来选择特征的代码如下:

1
2
3
4
5
6
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

# 参数 K 为选择的特征个数
# 返回值为特征选择后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)

d. 互信息

使用 feature_selection 库的 SelectKBest 类结合最大信息系数法来选择特征的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
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)

2. 包裹式(Wrapper)

与过滤式不考虑后续学习器不同,包裹式直接把最终将要使用的学习器的性能作为特征子集的评价准则。换言之,包裹式的目的就是为给定学习器选择最有利其性能、“量身定做”的特征子集。

a. 递归特征消除法

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

1
2
3
4
5
6
7
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)

b. 现代智能优化算法

将特征子集的选择看作是一个优化问题,这样就可以使用一些启发式的现代智能优化算法,例如:遗传算法、模拟退火算法等。

3. 嵌入式(Embedding)

在过滤式和包裹式的特征选择方法中,特征选择过程与学习器训练过程有明显分别;与此不同,嵌入式是将特征选择过程与学习器训练过程融为一体,两者在同一个优化过程中完成,即在学习器训练过程中自动地进行了特征选择。

a. L1 正则化

L1 正则化更易于获得“稀疏”解,即它求得的 w 会有更少的非零分量,也就意味着初始的 d 个特征中仅有对应着 w 的非零分量的特征才会出现在最终的模型中,进而达到了特征选择的效果。使用 feature_selection 库的 SelectFromModel 类结合带 L1 正则项的逻辑回归模型,来选择特征的代码如下:

1
2
3
4
5
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression

# 返回值为特征选择后的数据
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)

参考文献