最近在看吴恩达的深度学习机器学习课程。地址:deeplearningai。课程在机器学习特征工程的课程中提到特征选择。在机器学习项目生命周期里,特征工程占据很大的比重,特征工程关乎最终模型性能的好坏,正所谓“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”。而特征选择是特征工程的一个重要问题,本文结合【机器学习】特征选择(Feature Selection)方法汇总一文,一起探讨特征工程里面的特征选择。
特征选择的目标是选择最优特征的子集,将一些不相关或者冗余的特征剔除,优化特征向量,避免不相关或冗余特征的干扰,提高模型的精度,提升模型的效率。另一方面在做特征选择过程中,能够协助理解数据产生的过程,理解特征的分布情况,有助于训练机器学习模型。特征选择的一般流程:
根据特征选择的形式,结合吴恩达的课程,将特征选择分为三大类:
发散性
或相关性
对各个特征进行评分,设定阈值或者待选择特征的个数进行筛选。思想:分别对每个特征 x i x_i xi计算其相对于类别标签y的信息量 S i g n a l ( i ) Signal(i) Signal(i),得到n个结果。然后将n个 S i g n a l ( x ) Signal(x) Signal(x)按照从大到小排序,输出前k个特征。其中计算信息量的有以下方法:
Pearson系数能够衡量特征和标签之间关系的方法,计算速度快,易于计算,但是有明显的缺点是,作为特征排序机制,只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应关系,Pearson相关性也可能接近0(如何理解Pearson系统?)。Pearson系数结果的取值区间为[-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)
print("Lower noise:", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise:", pearsonr(x, x + np.random.normal(0, 10, size)))
from sklearn.feature_selection import SelectKBest
# 选择K个最好的特征,返回选择特征后的数据
# 第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,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)
经典的卡方检验是检验类别型变量对类别型变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量:
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 #iris数据集
#选择K个最好的特征,返回选择特征后的数据
X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
经典的互信息也是评价类别型变量对类别型变量的相关性的,互信息公式如下:
距离相关系数是为了克服Pearson相关系数的弱点而生的。在 x x x和 x 2 x^2 x2 这个例子中,即便Pearson相关系数是 0 ,也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是 0 ,那么就可以说这两个变量是独立的。
from scipy.spatial.distance import pdist, squareform
import numpy as np
import copy
def distcorr(Xval, Yval, pval=True, nruns=500):
""" Compute the distance correlation function, returning the p-value."""
X = np.atleast_1d(Xval)
Y = np.atleast_1d(Yval)
if np.prod(X.shape) == len(X):
X = X[:, None]
if np.prod(Y.shape) == len(Y):
Y = Y[:, None]
X = np.atleast_2d(X)
Y = np.atleast_2d(Y)
n = X.shape[0]
if Y.shape[0] != X.shape[0]:
raise ValueError('Number of samples must match')
a = squareform(pdist(X))
b = squareform(pdist(Y))
A = a - a.mean(axis=0)[None, :] - a.mean(axis=1)[:, None] + a.mean()
B = b - b.mean(axis=0)[None, :] - b.mean(axis=1)[:, None] + b.mean()
dcov2_xy = (A * B).sum() / float(n * n)
dcov2_xx = (A * A).sum() / float(n * n)
dcov2_yy = (B * B).sum() / float(n * n)
dcor = np.sqrt(dcov2_xy) / np.sqrt(np.sqrt(dcov2_xx) * np.sqrt(dcov2_yy))
if pval:
greater = 0
for i in range(nruns):
Y_r = copy.copy(Yval)
np.random.shuffle(Y_r)
if distcorr(Xval, Y_r, pval=False) > dcor:
greater += 1
return (dcor, greater / float(nruns))
else:
return dcor
from sklearn.datasets import load_iris
import pandas as pd
import numpy as np
import dcor
iris = load_iris()
iris_df = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
columns=iris['feature_names'] + ['target'])
print("dcor distance correlation = {:.3f}".format(
dcor.distance_correlation(iris_df['sepal length (cm)'], iris_df['petal length (cm)'])))
过滤特征选择法还有一种方法不需要度量特征 x i x_i xi 和类别标签 y y y 的信息量。这种方法先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。
from sklearn.feature_selection import VarianceThreshold
X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
# 方差选择法,返回值为特征选择后的数据
# 参数threshold为方差的阈值
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
print(sel.fit_transform(X))
方差选择的逻辑并不是很合理,这个是基于各特征分布较为接近的时候,才能以方差的逻辑来衡量信息量。但是如果是离散的或是仅集中在几个数值上,如果分布过于集中,其信息量则较小。而对于连续变量,由于阈值可以连续变化,所以信息量不随方差而变。 实际使用时,可以结合cross-validate进行检验。
基本思想:基于hold-out方法,对于每一个待选的特征子集,都在训练集上训练一遍模型,然后在测试集上根据误差大小选择出特征子集。需要先选定特定算法,通常选用普遍效果较好的算法, 例如Random Forest, SVM, KNN等等。常用的包装法包括了前向选择法,后向剔除法,迭代剔除法等。
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择
SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
特征选择算法可以被视为搜索技术和评价指标的结合。前者提供候选的新特征子集,后者为不同的特征子集打分。 最简单的算法是测试每个特征子集,找到究竟哪个子集的错误率最低。这种算法需要穷举搜索空间,难以算完所有的特征集,只能涵盖很少一部分特征子集。 选择何种评价指标很大程度上影响了算法。而且,通过选择不同的评价指标,可以把特征选择算法分为三类:包装类、过滤类和嵌入类方法。