特征工程 - 机器学习

特征工程

特征 => 数据中抽取出来的对结果预测有用的信息。
特征工程 => 使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。

更好的特征意味着

  • 更强的灵活度
  • 可用更简单的模型
  • 更好的结果

本文介绍一些简单的特征工程方法以及特征选择和特征降维的方法。

范围调整, 归一化

# X是numpy数组(矩阵或向量)
# min max
min_max_scaler = sklearn.preprocessing.MinMaxScaler()
X_minmax = min_max_scaler.fit_transform(X)
# 0均值,单位方差
X_scaled = sklearn.preprocessing.scale(X)
#X_scaled.mean(axis=0);X_scaled.std(axis=0)

scaler = sklearn.preprocessing.StandardScaler().fit(X)
scaler.transform(X2)

统计

# 创造数据
series = pandas.Series(np,random.randn(500))
# 统计描述,参数为百分比点
series.describe(percentiles=[.05, .25, .75, .95])

离散化

pandas的cut和qcut函数可以将一个序列离散到几个区间中.

特征处理-类别型

  • one-hot编码/哑变量

将多种类别进行编码时每个类别用一个长度为类别数的01序列表示,将类别对应的位置置1,其它位置置0,别名是哑变量.这是sklearn的标签值的存储方式,pandas的get_dummies也可以得到此编码,特征表示由一列变为多列.

  • Histogram映射

若输入X中包含性别这一特征,目标y为兴趣爱好.则可以通过统计每一性别在爱好上的分布作为一个特征来表征每种性别.如男性:[1/4(散步),1/2(看电视),1/4(其它)];再比如每一年龄中各兴趣的分布.

特征处理-文本型

  • 词袋bag of words

文本数据预处理后,去掉停用词,剩下的词组成的list,在词库中的映射稀疏向量.通俗讲,就是矩阵的每行是对应的一篇文档的各个词或词组的词频.

Python处理可以使用sklearn.feature_extraction.text.CountVectorizer,以压缩的稀疏矩阵形式存储.支持n-gram,即多个连续词组成的词组.需设置参数ngram_range,token_pattern.

  • word2vec

两个单词之间建立一个向量,具有距离的概念.

工具: Google word2vec

特征选择

如果存在冗余特征或某些特征对结果会有负影响(噪声),则可以进行特征选择.与降维不同,降维做的是特征的计算组合构建新的特征.

  • 过滤型 (单个特征与结果的相关度)
  • 包裹型(递归特征删除)
  • 嵌入型(基于L1正则化)

过滤型

筛选器: 评估单个特征和结果值之间的相关程度,排序留下Top相关的特征部分。
相关度: Pearson相关系数,互信息,距离相关度.
缺点: 没有考虑到特征之间的关联作用,可能把有用的关联特征误踢掉。

相关的python包(sklearn中)有SelectKBest,SelectPercentile,GenericUnivariateSelect.

  1. 相关性
    对于两个变量,可以用皮尔逊相关系数(Pearson correlation coefficient)计算相关性.代码可用scipy.stat.pearsonr([1,2,3],[1,2,3.2])来计算Cor(X1,X2)。对于每组特征,如果相关性较高,可以认为存在冗余的特征,保留其中一个。
    缺点:只能检测出线性关系,无法检测其它关系(如二次函数关系)。
  2. 互信息量
    香农信息熵:

\[H(X)=-\sum_{i=1}^n p(X_i)log_2 p(X_i) \]

对于两个相关联的特征X、Y,若P(X)=0.1,P(Y)=0.9,则可用scipy.stats.entropy([0.1,0.9],base=2)来计算,其中基数为2是log函数的基数,也可以换成10、e等对结果的判断影响不大。下面扩展上述公式使之适用于多特征。
互信息量定义:

\[I(X;Y)=\sum_{i=1}^m \sum_{j=1}^n P(X_i,Y_j)log_2 \frac{P(X_i,Y_j)}{P(X_i)P(Y_j)} \]

归一化(使结果限定在[0,1]区间),需要将其除以每个独立变量的信息熵之和:

\[NI(X;Y)=\frac{I(X;Y)}{H(X)H(Y)} \]

缺点:计算每对特征之间的归一化互信息量时的计算量比较大,扔掉了独立使用时没有用处的特征。但实际情况往往是,一些特征看起来跟目标变量完全独立,但当它们组合在一起时就有效用了。要保留这些特征,我们需要包裹型封装器。

包裹型

把特征选择看做一个特征子集搜索问题,筛选各种特征子集,用模型评估效果。
典型的包裹型算法为递归特征消除法(Recursive Feature Elimination, RFE), 它只选取具有最大绝对权重的特征.

流程:

  1. 用全量特征跑一个模型
  2. 根据线性模型的系数(体现相关性),删掉5-10%的弱特征,观察准确率(或其它衡量指标)的变化
  3. 逐步进行,直至准确率等出现大的下滑停止

Python包sklearn.feature_selection中含有各种优秀的封装器类.代表性的有RFE,它会把一个估算器和预期数量的特征当做参数,然后只要发现一个足够小的特征子集,就在这个特征集合里训练估算器。另外还有RFECV在交叉验证循环中执行RFE来找最优的特征数量。

from sklearn.feature_selection import RFE
max_features = 4
rfe = RFE(model, max_features).fit(X,Y) # 这里的model可选择sklearn的大多数模型,如LinearRegression.
# 而KNeighborsRegressor由于不支持特征加权,所以不能用RFE
mask = rfe.support_ # 布尔值列表,被选择的特征对应True

另外常用的特征选择方法有: 迭代选择(前向选择与后向排除法).

前向选择是从没有特征开始,逐步寻找最好的特征进行添加. 第一次迭代,仅使用一个特征, 遍历N个特征,从中选择出具有最佳交叉验证准确率的特征. 第二次迭代,从剩余的N-1个特征中选择一个与已确定的特征组合,选择最佳. 而每次交叉验证需要构建k个模型, 因此总共会构建 k[N+(N-1)+...+1] 个模型.
后向排除法(反向消除)是从所有特征中逐个进行删除, 计算量与前向相同.
迭代选择相比全局搜索计算复杂度低很多,但是当特征数量较大时,计算量仍然较大.

嵌入型

根据模型来分析特征的重要性(通过分析产生的模型权重等)。常见的方式为用正则化方式来做特征选择。

基于L1的特征选择:

使用L1正则的线性模型在训练之后许多系数会是0,因此可以从这个模型中选择非0的系数.sklearn中的feature_selection.SelectFromModel可以达到此目的.这里可以使用的模型包括linear_model.Lasso,LogisticRegression(回归),svm.LinearSVC(分类).

模型内置特征选择方法: 某些模型,如线性回归、逻辑回归(特征加权)、决策树(特征重要度)、集成方法(随机森林每棵树采用子特征)。这些特征选择方法相比通用的方法计算更有效率,可以捕获特征被随机噪声替代后的模型准确度下降程度。


特征降维

特征降维与核函数的作用正好相反。核函数主要的工作是增加维度,把原本在低维度里的样本,映射到更高的维度里,将本来不可以线性分类的点,变成可以线性分类的。

  • 特征抽取法
    将原始特征空间转换为一个低维特征空间,方法:
    • 主成分分析(Principal Component Analysis,PCA) (线性)
    • 线性判别式分析(Linear Discriminant Analysis,LDA)
    • 多维标度法(MultiDimentsional Scaling,MDS) (非线性)

删减特征的意义

  1. 多余的特征可能会影响或误导学习器。(支持向量机是一个例外,喜欢高维空间)
  2. 越多的特征意味着越多的参数需要调整,过拟合风险较大
  3. 用来解决问题的维度可能只是虚高,真实维度可能比较小
  4. 维度越少训练越快,可以进行更多的实验尝试
  5. 数据可视化往往受限于二维或三维上
posted @ 2018-05-25 10:48  康行天下  阅读(490)  评论(0编辑  收藏  举报