特征工程(Feature Engineering)

1、特征工程的重要性

有这么一句话在业界普遍流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已,在楼主本人亲自作的机器学习项目中也发现,不一样的机器学习算法对结果的准确率影响有限,好的特征工程以及数据集才影响到了模型本质的结果。那特征工程究竟是什么呢?顾名思义,其本质是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。经过总结和概括,人们认为特征工程包括如下方面:html

该图引用于别人的博客,在文章的最后能够看到参考连接。算法

但根据我我的的理解,这张图虽然比较全面,可是我认为特征工程的核心工做是一个线性的阶段性的过程,而不是图中描述的不少并行化过程。数组

特征工程主要有三个主要阶段,本文也将从这三个阶段讲解特征工程:一、特征清洗、数据清洗。二、特征处理、数据处理。三、特征选择网络

特征是机器学习系统的原材料,对最终模型的影响是毋庸置疑的。定义:特征工程是将原始数据转化为特征,更好表示预测模型处理的实际问题,提高对于未知数据的准确性。它是用目标问题所在的特定领域知识或者自动化的方法来生成、提取、删减或者组合变化获得特征。app

数据特征会直接影响你使用的预测模型和实现的预测结果。准备和选择的特征越好,则实现的结果越好。影响预测结果好坏的因素:模型的选择、可用的数据、特征的提取dom

优质的特征每每描述了数据的固有结构。大多数模型均可以经过数据中良好的结构很好的学习,即便不是最优的模型,优质的特征也能够获得不错的效果。优质特征的灵活性可让你使用简单的模型运算的更快,更容易理解,更容易维护。优质的特征能够在使用不是最优的模型参数的状况下获得不错的预测结果,这样你就没必要费力去选择最适合的模型和最优的参数了。机器学习

首先,咱们你们都知道,数据特征会直接影响咱们模型的预测性能。你能够这么说:“选择的特征越好,最终获得的性能也就越好”。这句话说得没错,但也会给咱们形成误解。事实上,你获得的实验结果取决于你选择的模型、获取的数据以及使用的特征,甚至你问题的形式和你用来评估精度的客观方法也扮演了一部分。此外,你的实验结果还受到许多相互依赖的属性的影响,你须要的是可以很好地描述你数据内部结构的好特征。函数

(1)特征越好,灵活性越强工具

  只要特征选得好,即便是通常的模型(或算法)也能得到很好的性能,由于大多数模型(或算法)在好的数据特征下表现的性能都还不错。好特征的灵活性在于它容许你选择不复杂的模型,同时运行速度也更快,也更容易理解和维护。性能

(2)特征越好,构建的模型越简单

  有了好的特征,即使你的参数不是最优的,你的模型性能也能仍然会表现的很nice,因此你就不须要花太多的时间去寻找最有参数,这大大的下降了模型的复杂度,使模型趋于简单。

(3)特征越好,模型的性能越出色

  显然,这一点是毫无争议的,咱们进行特征工程的最终目的就是提高模型的性能。

惰性是推进科技发展的动力,不少算法工程也在思考,能不能经过模型的方式来自动的学习和构成特征呢?"全部的想法都会有实现的一天",如今市面上有效的特征构造模型有 FM(Factorization Machine 因子分解机)、深度学习(提取训练好的模型中隐层做为特征)能够本身学习出一些特征以及特征之间的组合关系,有人使用过主题模型 LDA、word2vec、FM 来做为特征生成的模型,将模型训练的中间结果,好比 LDA 的主题分布、word2vec 生成的词向量用于 LR 这样的线性模型,线上测试效果都很是好。

经过上面的例子咱们能够知道特征构造大体思路,也就是从场景目标出发,去找出与之有关的因素。可是在实际场景除了天马行空想特征以外,还须要对于想出来的特征作一可行性评估:获取难度、覆盖度、准确度等,好比笛卡尔积会使得特征维度增长的很是快,会出现大量覆盖度低的特征,若是把这些覆盖度低的特征加入到模型中训练,模型会很是不稳定;然而这一系列的工做就是传说中的特征工程。

下面从特征工程的多个子问题全方位分析特种工程。

 

2、特征工程的子问题

 

  经过特征提取,咱们能获得未经处理的特征,这时的特征可能有如下问题: 

  • 不属于同一量纲:即特征的规格不同,不可以放在一块儿比较。无量纲化能够解决这一问题。
  • 信息冗余:对于某些定量特征,其包含的有效信息为区间划分,例如学习成绩,倘若只关心“及格”或不“及格”,那么须要将定量的考分,转换成“1”和“0”表示及格和未及格。二值化能够解决这一问题。
  • 定性特征不能直接使用:某些机器学习算法和模型只能接受定量特征的输入,那么须要将定性特征转换为定量特征。最简单的方式是为每一种定性值指定一个定量值,可是这种方式过于灵活,增长了调参的工做。一般使用哑编码的方式将定性特征转换为定量特征:假设有N种定性值,则将这一个特征扩展为N种特征,当原始特征值为第i种定性值时,第i个扩展特征赋值为1,其余扩展特征赋值为0。哑编码的方式相比直接指定的方式,不用增长调参的工做,对于线性模型来讲,使用哑编码后的特征可达到非线性的效果。
  • 存在缺失值:缺失值须要补充。
  • 信息利用率低:不一样的机器学习算法和模型对数据中信息的利用是不一样的,以前提到在线性模型中,使用对定性特征哑编码能够达到非线性的效果。相似地,对定量变量多项式化,或者进行其余的转换,都能达到非线性的效果。

在模型训练过程当中,咱们会对训练数据集进行抽象、抽取大量特征,这些特征中有离散型特征也有连续型特征。若此时你使用的模型是简单模型(如LR),那么一般咱们会对连续型特征进行离散化操做,而后再对离散的特征,进行one-hot编码或哑变量编码。这样的操做一般会使得咱们模型具备较强的非线性能力。

1. 特征清洗、数据清洗

在实际生产环境中,业务数据并不是如咱们想象那样完美,可能存在各类问题,好比上报异常、恶意做弊行为、爬虫抓取等。为了让模型可以学到真实的行为规律,咱们须要对已经构造的原始特征进行清洗,排除掉脏数据。主要包括一下两个方面:

1. 结合业务状况进行数据的过滤,例如去除 crawler 抓取,spam,做弊等数据。

2. 异常点检测,采用异常点检测算法对样本进行分析,经常使用的异常点检测算法包括

    • 误差检测,例如聚类,最近邻等。
    • 基于统计的异常点检测算法

例如极差,四分位数间距,均差,标准差等,这种方法适合于挖掘单变量的数值型数据。全距(Range),又称极差,是用来表示统计资料中的变异量数(measures of variation) ,其最大值与最小值之间的差距;四分位距一般是用来构建箱形图,以及对几率分布的简要图表概述。

    • 基于距离的异常点检测算法,

主要经过距离方法来检测异常点,将数据集中与大多数点之间距离大于某个阈值的点视为异常点,主要使用的距离度量方法有绝对距离 ( 曼哈顿距离 ) 、欧氏距离和马氏距离等方法。

    • 基于密度的异常点检测算法

考察当前点周围密度,能够发现局部异常点,例如 LOF 算法 

2. 特征处理、数据处理

1) 连续型特征

  • 归一化

归一化有不少好处,好比能够加快梯度降低寻找最优解的速度,能够提高模型的精度,同时也使得特征之间具备可比性,固然全部的事情都是双面的,通过归一化处理以后,会损失掉源特征的一些信息,但这个损失相对应带来的好处咱们仍是能够接受的。

归一化能够分为如下三种类型:

  • 线性归一化:

这种归一化方法比较适用在数值比较集中的状况。这种方法有个缺陷,若是 max 和 min 不稳定,很容易使得归一化结果不稳定,使得后续使用效果也不稳定。实际使用中能够用经验常量值来替代 max 和 min。

使用preproccessing库的MinMaxScaler类对数据进行区间缩放的代码以下:

from sklearn.preprocessing import MinMaxScaler
MinMaxScaler().fit_transform(iris.data)
  • 标准化归一化:

在彻底随机的状况下,咱们能够假设咱们的数据是符合标准正态分布的,也就是均值为 0,标准差为 1;那么其归一化函数以下:

from sklearn.preprocessing import StandardScaler
#标准化归一化
StandardScaler().fit_transform(iris.data)
  • 非线性归一化:

在数据分化比较大的场景中,有些数值很大,有些很小。经过一些数学函数,将原始值进行映射。该方法包括 log、指数,正切等。须要根据数据分布的状况,决定非线性函数的曲线,好比 log(V, 2) 仍是 log(V, 10) 等。

实际业务中咱们能够根据本身对数据的理解进行不一样的归一化方法,下面是手游推荐业务使用到的归一化函数:

正向特征,特征越大打分越大,例如付费金额

,其中

反向特征,特征越大打分越小,例如首次付费距离当前天数

,其中

汇总特征,取均值,例如活跃天=score/天数

这样的归一化为啥会比其余归一化更好呢!或许数学家们能够从公式上进行推到证实,而咱们的理解是,其实每一个业务的数据都会有特定的分布,好比彻底随机的时候数据知足正态分布,那么所选择的方法必需要符合这种数据分布的特色,通常状况下会根据本身对业务数据的了解,对公式进行调整,可是归一化的思路仍是跟上面提到的同样的。

  • 离散化

离散化能够理解为将连续的特征值转换为为离散的特征值的过程,也称为分区或分箱。离散化对于线性模型来讲是很是有帮助的,缘由是它能够将目标值 Y 与特征值的线性转为目标值与离散化以后转化的向量里的每一个元素之间的线性关系,这样向量的每一个份量都有一个权重,引入了非线性,提高了模型拟合能力。以前作过实验,使用一样的特征,有通过离散化处理的特征训练出来的模型,会比没有通过离散化训练出来的模型效果好 20%以上;如今使用比较多的特征离散化的方法有,等频离散、等距离散、树模型离散。

arr = np.random.randn(20)
pd.cut(arr , 4)

[(-1.234, -0.551], (-1.234, -0.551], (-0.551, 0.13], (0.81, 1.491], (-1.234, -0.551], ..., (-0.551, 0.13], (-0.551, 0.13], (0.13, 0.81], (0.81, 1.491], (0.81, 1.491]]
Length: 20
Categories (4, interval[float64]): [(-1.234, -0.551] < (-0.551, 0.13] < (0.13, 0.81] < (0.81, 1.491]]
arr = np.random.randn(20)
pd.cut(arr , [-5,-1,0,1,5])

[(0, 1], (-1, 0], (0, 1], (-1, 0], (0, 1], ..., (-5, -1], (-1, 0], (-5, -1], (0, 1], (-5, -1]]
Length: 20
Categories (4, interval[int64]): [(-5, -1] < (-1, 0] < (0, 1] < (1, 5] 

 

2) 离散型特征

一些属性是类别型而不是数值型,举一个简单的例子,由{红,绿、蓝}组成的颜色属性,最经常使用的方式是把每一个类别属性转换成二元属性,即从{0,1}取一个值。所以基本上增长的属性等于相应数目的类别,而且对于你数据集中的每一个实例,只有一个是1(其余的为0),这也就是独热(one-hot)编码方式(相似于转换成哑变量)。

若是你不了解这个编码的话,你可能会以为分解会增长不必的麻烦(由于编码大量的增长了数据集的维度)。相反,你可能会尝试将类别属性转换成一个标量值,例如颜色属性可能会用{1,2,3}表示{红,绿,蓝}。这里存在两个问题:首先,对于一个数学模型,这意味着某种意义上红色和绿色比和蓝色更“类似”(由于|1-3| > |1-2|)。除非你的类别拥有排序的属性(好比铁路线上的站),这样可能会误导你的模型。而后,可能会致使统计指标(好比均值)无心义,更糟糕的状况是,会误导你的模型。仍是颜色的例子,假如你的数据集包含相同数量的红色和蓝色的实例,可是没有绿色的,那么颜色的均值可能仍是获得2,也就是绿色的意思。

one-hot编码和dummy编码是比较像的两种编码,二者的区别是,若是离散型特征有5个属性,one-hot编码会生成5个特征,而dummy编码则生成4个。

from sklearn.preprocessing import OneHotEncoder
data = iris.target.reshape((-1,1))
print(data.shape)
data = OneHotEncoder().fit_transform(data)
print(data.shape)

(150, 1)
(150, 3)

 

3) 时间型特征

时间特征既能够看做是连续型,也能够看做是离散型。

连续型:持续时间(单页浏览时长)、间隔时间(上次购买、点击离如今的时间)

离散型:哪一个时段(0-24),星期几,工做日/周末/法定假日。

4) 文本型特征

文本型特征常见的处理方法有两类,第一类采用最普通的词袋(bag of words)模型,以及在此基础上加入ngram扩充词袋,以及使用tfidf加权特征值。第二类是基于Word2vec生成词向量。

  • 词袋模型

文本数据预处理后,去掉停用词,剩下的词组成的list, 在词库中的映射稀疏向量,这就是词袋模型。如下摘自sklearn文档

  • 词袋模型 + ngram

因为普通的词袋模型没有很好的考虑上下文的关系,只把每一个单词当作单个特征来处理,所以就有了ngram改进普通的词袋模型,普通的词袋模型是1-gram,两个单词为2-gram,以此类推。

  • 词袋模型 + ngram + tfidf加权

本来的词袋模型实际上是表征的词袋中每个词在该文档中的出现次数 ,但若是这个词仅在因此样本中都出现了不少次,该词的特征值就失去了良好的特征表达能力,所以就出现了tfidf来平衡权值。TFIDF的主要思想是:若是某个词或短语在一篇文章中出现的频率TF高,而且在其余文章中不多出现,则认为此词或者短语具备很好的类别区分能力,适合用来分类。TFIDF其实是:TF * IDF,TF词频(Term Frequency),IDF反文档频率(Inverse Document Frequency)。

在一份给定的文件里,词频(term frequency,TF)指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数(term count)的归一化,以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词数,而无论该词语重要与否。)对于在某一特定文件里的词语 t_{i} 来讲,它的重要性可表示为:\mathrm{tf_{i,j}} = \frac{n_{i,j}}{\sum_k n_{k,j}}

以上式子中 n_{i,j} 是该词t_{i} 在文件d_{j}中的出现次数,而分母则是在文件d_{j}中全部字词的出现次数之和。

逆向文件频率(inverse document frequency,IDF)是一个词语广泛重要性的度量。某一特定词语的IDF,能够由总文件数目除以包含该词语之文件的数目,再将获得的商取对数获得

\mathrm{idf_{i}} =  \log \frac{|D|}{|\{j: t_{i} \in d_{j}\}|},有时候为了防止出现0的状况,会加上平滑\text{idf}(t) = log{\frac{1 + n_d}{1+\text{df}(d,t)}} + 1

  • word2vec

前面提到的基于词袋的三种特征方法是天然语言处理之前的方法,都是会生成很稀疏的矩阵,并且对表达词与词之间的类似性能力有限。而word2vec能够将天然语言中的字词转为计算机能够理解的稠密向量(Dense Vector)。Python版的word2vec工具箱:gensim

2013年,Google开源了一款用于词向量计算的工具——word2vec,引发了工业界和学术界的关注。首先,word2vec能够在百万数量级的词典和上亿的数据集上进行高效地训练;其次,该工具获得的训练结果——词向量(word embedding),能够很好地度量词与词之间的类似性。随着深度学习(Deep Learning)在天然语言处理中应用的普及,不少人误觉得word2vec是一种深度学习算法。其实word2vec算法的背后是一个浅层神经网络。另外须要强调的一点是,word2vec是一个计算word vector的开源工具。当咱们在说word2vec算法或模型的时候,其实指的是其背后用于计算word vector的CBoW模型和Skip-gram模型。不少人觉得word2vec指的是一个算法或模型,这也是一种谬误。在本文,因为篇幅缘由,就不对word2vec作详细的原理介绍,之后会专门写一篇介绍Word2vec原理的文章。

 

5) 统计型特征 

当前样本集的各类统计信息,包括均值、最大值、1分位数、4分位数等。

import pandas as pd
import numpy as np series = pd.Series(np.random.randn(500)) series.describe() count 500.000000 mean -0.063427 std 1.007670 min -3.032698 25% -0.749055 50% 0.001290 75% 0.607432 max 2.900834 dtype: float64

6) 组合特征(交叉特征)

  • 简单特征组合:拼接型

1.user_id&&category: 10001&&女裙,10002&&男士牛仔

2.user_id&&style:10001&&蕾丝,10002&&全棉

实际应用过程当中不会直接将用户id号和商品组合而产生很是稀疏的矩阵,会事先对用户作一个聚类。

  • 模型特征组合:GBDT

GBDT + LR是一套经典的特征组合+训练的方式,最先由Facebook提出。

思路大概是用先用GBDT训练模型,因为树模型是具备很好的解释性的,从根节点到叶子节点的路径就是一条特征组合,而后能够将组合特征和原始特征一块儿训练。

7) 缺失值处理

在实际业务中,可能会由于各类缘由会形成数据的缺失,好比某些用户年龄、性别、设备这类型的特征没法获取到,同时线上模型又有使用这些类型的特征,那么缺失了这些特征的用户在线上打分的时候会出现比较大的误差;一般会有几种方式来进行处理:数值型特征可使用均值或者中位数进行简单的替换,年龄这类型的特征能够经过关系链进行加权打分,固然也能够经过把缺失的所有都归为一类,用户默认值来替代。

固然对于新用户或者新 item 来讲其实也是属于一种缺失值状况,对于这种状况已经属于领一个很是大的领域,那就是推荐系统的启动问题。对于冷启动我问题,如今的作法会从两个方面着手,一种是经过集体智慧来解决,另一种是经过网络模型;第一种方法就是使用协同过滤的思想,与这个新用户相似的用户表现来知道新用户的推荐。第二种利用网络把 item 周围信息考虑进去,好比下面会提到的层次平滑,热传导模型也能够经过引入基础属性到二部图中,达到解决冷启动问题。

 

3. 特征选择

当数据预处理完成后,咱们须要选择有意义的特征输入机器学习的算法和模型进行训练。一般来讲,从两个方面考虑来选择特征:

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

特征选择的缘由是由于特征维度过高,可能出现冗余:部分特征的相关度过高了,消耗计算性能;也可能会出现噪声:部分特征是对预测结果没有帮助甚至有负影响。 

特征选择的目的是选择模型最优特征子集。特征与特征之间多多少少会有一些相互做用,好比有些特征是包含其余特征,有些特征与另外一些特征存在相关性的,也有一些特征须要与其余特征组合起来才能起做用,还有一些特征是会存在负相关的,若是只使用正是由于特征之间的这些关系,合理的选择适合的特征集合对于模型效果有很是大的做用。现有的特征选择方法能够大致分红三种类型:

  • Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
  • Wrapper:包装法,根据目标函数(一般是预测效果评分),每次选择若干特征,或者排除若干特征。
  • Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,获得各个特征的权值系数,根据系数从大到小选择特征。相似于Filter方法,可是是经过训练来肯定特征的优劣。

特征选择主要有两个目的:

  • 减小特征数量、降维,使模型泛化能力更强,减小过拟合;
  • 加强对特征和特征值之间的理解。

1) Filter(过滤法)

这种方法是衡量单个特征值与目标变量也就是样本 label 值之间的关联。但这种方法的缺点是没有考虑到特征之间的关联,有可能把有用的关联特征过滤掉。

对于分类问题(y离散),可采用:
    卡方检验,互信息
对于回归问题(y连续),可采用:
    皮尔森相关系数,最大信息系数

  • 互信息和最大信息系数 (Mutual information and maximal information coefficient (MIC)

经典的互信息(互信息为随机变量X与Y之间的互信息I(X;Y)I(X;Y)为单个事件之间互信息的数学指望)也是评价定性自变量对定性因变量的相关性的,互信息计算公式以下:

互信息直接用于特征选择其实不是太方便:一、它不属于度量方式,也没有办法归一化,在不一样数据及上的结果没法作比较;二、对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),一般变量须要先离散化,而互信息的结果对离散化的方式很敏感。

  最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,而后把互信息取值转换成一种度量方式,取值区间在[0,1]。

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)

MIC的统计能力遭到了一些质疑 ,当零假设不成立时,MIC的统计就会受到影响。在有的数据集上不存在这个问题,但有的数据集上就存在这个问题。

  • 卡方检验

经典的卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有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
X.shape
(150, 4)
X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
X_new.shape
(150, 2)
  • Pearson相关系数

皮尔森相关系数是一种最简单的,能帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为[-1,1],-1表示彻底的负相关,+1表示彻底的正相关,0表示没有线性相关。

  Pearson Correlation速度快、易于计算,常常在拿到数据(通过清洗和特征提取以后的)以后第一时间就执行。Scipy的 pearsonr 方法可以同时计算 相关系数 和p-value.

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)的输入为特征矩阵和目标向量
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))
>>>
# 输出为二元组(sorce, p-value)的数组
Lower noise (0.71824836862138386, 7.3240173129992273e-49)
Higher noise (0.057964292079338148, 0.31700993885324746)
  • 基于模型的特征排序 (Model based ranking)

这种方法的思路是直接使用你要用的机器学习算法,针对每一个单独的特征和响应变量创建预测模型。假如特征和响应变量之间的关系是非线性的,能够用基于树的方法(决策树、随机森林)、或者扩展的线性模型 等。基于树的方法比较易于使用,由于他们对非线性关系的建模比较好,而且不须要太多的调试。但要注意过拟合问题,所以树的深度最好不要太大,再就是运用交叉验证

在我以前讲解随机森林模型的博客中介绍了随机森林的一个重要特性OOB估计,能够在不进行交叉验证的状况下高效的计算特征对模型的重要程度。

from sklearn.cross_validation import cross_val_score, ShuffleSplit
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestRegressor
import numpy as np

# Load boston housing dataset as an example
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]

rf = RandomForestRegressor(n_estimators=20, max_depth=4)
scores = []
# 单独采用每一个特征进行建模,并进行交叉验证
for i in range(X.shape[1]):
    score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2",  # 注意X[:, i]和X[:, i:i+1]的区别
                            cv=ShuffleSplit(len(X), 3, .3))
    scores.append((format(np.mean(score), '.3f'), names[i]))
print(sorted(scores, reverse=True))
  • 方差选择法

这种方法和前几种方法不太同样,前几种方法是计算单个特征与结果值之间的相关程度从而删选特征,这种方法仅从特征的统计特性来考虑,没有考虑和结果值之间的相关度。

假设某特征的特征值只有0和1,而且在全部输入样本中,95%的实例的该特征取值都是1,那就能够认为这个特征做用不大。若是100%都是1,那这个特征就没意义了。当特征值都是离散型变量的时候这种方法才能用,若是是连续型变量,就须要将连续变量离散化以后才能用。并且实际当中,通常不太会有95%以上都取某个值的特征存在,因此这种方法虽然简单可是不太好用。能够把它做为特征选择的预处理,先去掉那些取值变化小的特征,而后再从接下来提到的的特征选择方法中选择合适的进行进一步的特征选择。

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]]
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])

 2) Wrapper(包装法)

Wrapper 这一类特征选择方法,应该来讲是比较科学的,可是也是很是耗时,工业界在生产环境中不多使用,很是耗时,也是一个 NP 复杂的问题,通常经过不断迭代,而后每次加入一个特征,来训练模型,使用模型评估好比 AUC 或者 MSE 等函数评估是否将特征加入到特征子集中。

递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,移除若干权值系数的特征,再基于新的特征集进行下一轮训练

sklearn官方解释:对特征含有权重的预测模型(例如,线性模型对应参数coefficients),RFE经过递归减小考察的特征集规模来选择特征。首先,预测模型在原始特征上训练,每一个特征指定一个权重。以后,那些拥有最小绝对值权重的特征被踢出特征集。如此往复递归,直至剩余的特征数量达到所需的特征数量。

RFECV 经过交叉验证的方式执行RFE,以此来选择最佳数量的特征:对于一个数量为d的feature的集合,他的全部的子集的个数是2的d次方减1(包含空集)。指定一个外部的学习算法,好比SVM之类的。经过该算法计算全部子集的validation error。选择error最小的那个子集做为所挑选的特征。

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)

 3) Embedded(包装法)

单变量特征选择方法独立的衡量每一个特征与响应变量之间的关系,另外一种主流的特征选择方法是基于机器学习模型的方法。有些机器学习方法自己就具备对特征进行打分的机制,或者很容易将其运用到特征选择任务中,例如回归模型,SVM,决策树,随机森林等等。

  • 基于惩罚项的特征选择法

以前我写的一篇文章对比了L一、L2正则化的区别,L1正则化具备截断性,L2正则化具备缩放效应,因此咱们能够很好的利用线性模型的两种正则化选择特征、  

使用L1范数做为惩罚项的线性模型(Linear models)会获得稀疏解:大部分特征对应的系数为0。当你但愿减小特征的维度以用于其它分类器时,能够经过 feature_selection.SelectFromModel 来选择不为0的系数。特别指出,经常使用于此目的的稀疏预测模型有 linear_model.Lasso(回归), linear_model.LogisticRegression 和 svm.LinearSVC(分类): 

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)
  • 基于树模型的特征选择法

GBDT在计算每一个节点的重要程度时能够同时用来作特征选择,RF能够用他的OOB估计来评价特征的重要程度

树模型中GBDT也可用来做为基模型进行特征选择,使用feature_selection库的SelectFromModel类结合GBDT模型,来选择特征的代码以下:

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier

#GBDT做为基模型的特征选择
SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)

 

4. 特征评估

前面写了不少特征构造和处理的方法,可能更多时间咱们更想知道一个特征是否真的靠谱,在时间有限的状况下,用贪心的思想,每次选择表现最好的特征加入到模型训练中,这个时候就会特征评估这个东西了,特征评估可能会从几个维度进行衡量:

一、特征自身的质量

    • 特征覆盖度,这个指标是衡量某个特征可以影响的样本量,通常状况下,会排查覆盖度特别低的
    • 特征的准确性,也就是说特征值是否考虑,会不会存在太多错误数据
    • 特征方差,衡量特征是否有区分度,好比 100 个训练样本,有 99 个是 0,那么这个特征方差就特别低,确定有问题。

二、特征与目标值的相关性

    • 相关系数
    • 单特征 AUC

5. 降维

当特征选择完成后,能够直接训练模型了,可是可能因为特征矩阵过大,致使计算量大,训练时间长的问题,所以下降特征矩阵维度也是必不可少的。常见的降维方法除了以上提到的基于L1惩罚项的模型之外,另外还有主成分分析法(PCA)和线性判别分析(LDA),线性判别分析自己也是一个分类模型。PCA和LDA有不少的类似点,其本质是要将原始的样本映射到维度更低的样本空间中,可是PCA和LDA的映射目标不同:PCA是为了让映射后的样本具备最大的发散性;而LDA是为了让映射后的样本有最好的分类性能。因此说PCA是一种无监督的降维方法,而LDA是一种有监督的降维方法。

from sklearn.decomposition import PCA

 #主成分分析法,返回降维后的数据
 #参数n_components为主成分数目
PCA(n_components=2).fit_transform(iris.data)

 

  

 

参考连接:

https://cloud.tencent.com/developer/article/1005443 

http://www.cnblogs.com/jasonfreak/p/5448385.html

http://www.javashuo.com/article/p-mldamdbd-bd.html

http://blog.csdn.net/sangyongjia/article/details/52440063

https://www.cnblogs.com/iloveai/p/word2vec.html

http://www.javashuo.com/article/p-actaxjun-bm.html

寒小阳-特征工程 

相关文章
相关标签/搜索