python 特征工程 概述

1 特征工程是什么?

2 数据预处理
2.1 无量纲化    
2.1.1 标准化    
2.1.2 区间缩放法    
2.1.3 标准化与归一化的区别  
2.2 对定量特征二值化  
2.3 对定性特征哑编码  
2.4 缺失值计算  
2.5 数据变换
2.6 异常点检测
2.6.1 偏差检测,例如聚类,最近邻等。
2.6.2 基于统计的异常点检测算法:四分位数间距,均差,标准差
2.6.3 基于距离的异常点检测算法
2.6.4 基于密度的异常点检测算法 LOF

3 特征选择  
3.1 Filter    
3.1.1 方差选择法    
3.1.2 相关系数法    
3.1.3 卡方检验    
3.1.4 互信息法  
3.2 Wrapper    
3.2.1 递归特征消除法  
3.3 Embedded    
3.3.1 基于惩罚项的特征选择法    
3.3.2 基于树模型的特征选择法

4 降维  
4.1 主成分分析法(PCA)  
4.2 线性判别分析法(LDA)

标准化与归一化的区别

简单来说,标准化是依照特征矩阵的处理数据,其通过求z-score的方法,将样本的特征值转换到同一量纲下。归一化是依照特征矩阵的处理数据,其目的在于样本向量在点乘运算或其他核函数计算相似性时,拥有统一的标准,也就是说都转化为“单位向量”

规则为l2的归一化公式如下:

from sklearn.preprocessing import Normalizer

#归一化,返回值为归一化后的数据
Normalizer().fit_transform(iris.data)

对定量特征二值化

from sklearn.preprocessing import Binarizer

#二值化,阈值设置为3,返回值为二值化后的数据
Binarizer(threshold=3).fit_transform(iris.data)

对定性特征哑编码

from sklearn.preprocessing import OneHotEncoder

#哑编码,对IRIS数据集的目标值,返回值为哑编码后的数据
OneHotEncoder().fit_transform(iris.target.reshape((-1,1)))

非线性归一化

包括 log、指数,正切等。需要根据数据分布的情况,决定非线性函数的曲线,比如 log(V, 2) 还是 log(V, 10) 等。

下面是手游推荐业务使用到的归一化函数:

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



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



汇总特征,取均值,例如活跃天


离散化

对原始值进行分段,具体如何分、分成几分,这里面又很多学问;离散化对于线性模型来说是非常有帮助的,原因是它可以将目标值 Y 与特征值的线性转为目标值与离散化之后转化的向量里的每个元素之间的线性关系,这样向量的每个分量都有一个权重,引入了非线性,提升了模型拟合能力。

之前做过实验,使用同样的特征,有经过离散化处理的特征训练出来的模型,会比没有经过离散化训练出来的模型效果好 20%以上;现在使用比较多的特征离散化的方法有,等频离散、等距离散、树模型离散。

数据平滑

在推荐场景中会有大量的点击率类型的特征,这类型的特征通常都是使用行为操作量/曝光量得到,这类统计类特征会受到行为操作与曝光量之间的关系的影响;比如同一个游戏的 banner 的随着曝光量的增长,点击量的增长率是会不断下降的,也就是说如果不做任何处理行为操作量/曝光量产生的特征对曝光量大的游戏是不公平的。

对于曝光量小 item 是有利的,极端的例子是曝光一次,点击一次,那么点击率就是 100%,这明显是不可能的;那么如何做呢?一种常用的方式是训练一个 beta(a,b)分布,使用(行为操作量 a)/(曝光量 a b);原理是我们可以把每次点击与不点击看成是一个伯努利分布,那么所有用户与所有游戏这种点击与不点击对可以看成是一个 beta 分布,从全局的角度学习到平滑因子;

还有一种方法是,既然不能对不同量级的曝光量进行比较,那我们可以把曝光量进行分段,同一个曝光量级的点击率进行比较。当然还有一种叫做层次平滑的算法,把游戏进行分类,如果单个游戏的曝光量很少,可以使用所述类的平均值进行平滑处理。

数据变换

from sklearn.preprocessing import PolynomialFeatures

#多项式转换
#参数degree为度,默认值为2
PolynomialFeatures().fit_transform(iris.data)

基于单变元函数的数据变换可以使用一个统一的方式完成,使用preproccessing库的FunctionTransformer对数据进行对数函数转换的代码如下:

from numpy import log1p
from sklearn.preprocessing import FunctionTransformer

#自定义转换函数为对数函数的数据变换
#第一个参数是单变元函数
FunctionTransformer(log1p).fit_transform(iris.data)

特征选择

特征选择的目的是选择模型最优特征子集。特征与特征之间多多少少会有一些相互作用,比如有些特征是包含其他特征,有些特征与另一些特征存在相关性的,也有一些特征需要与其他特征组合起来才能起作用,还有一些特征是会存在负相关的;正是因为特征之间的这些关系,合理的选择适合的特征集合对于模型效果有非常大的作用。

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

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

根据特征选择的形式又可以将特征选择方法分为3种:

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

Filter

方差选择法

使用方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。

from sklearn.feature_selection import VarianceThreshold

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

使用相关系数法,先要计算各个特征对目标值的相关系数以及相关系数的P值。

from sklearn.feature_selection import SelectKBest
from scipy.stats import pearsonr

#选择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.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

#选择K个最好的特征,返回选择特征后的数据
SelectKBest(chi2, k=2).fit_transform(iris.data, iris.target)
互信息法

为了处理定量数据,最大信息系数法被提出


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)

Wrapper

包裹式特征选择根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。这类方法的核心思想在于,给定了某种模型,及预测效果评价的方法,然后针对特征空间中的不同子集,计算每个子集的预测效果,效果最好的,即作为最终被挑选出来的特征子集。
注意集合的子集是一个指数的量级,故此类方法计算量较大。
故而针对如何高效搜索特征空间子集,就产生了不同的算法。其中有一种简单有效的方法叫贪婪搜索策略,包括前向选择与后向删除。在前向选择方法中,初始化一个空的特征集合,逐步向其中添加新的特征,如果该特征能提高预测效果,即得以保留,否则就扔掉。后向删除即是说从所有特征构成的集合开始,逐步删除特征,只要删除后模型预测效果提升,即说明删除动作有效,否则就还是保留原特征。要注意到,包裹式方法要求针对每一个特征子集重新训练模型,因此计算量还是较大的。
通常,将过滤式方法的高效与包裹式方法的高准确率进行结合,可得到更优的特征子集。混合特征选择过程一般由两个阶段组成:

1)使用Filter方法初步剔除大部分无关或噪声特征,只保留少量特征,从而有效地减小后续搜索过程的规模。
2)将剩余的特征连同样本数据作为输入参数传递给Wrapper选择方法,以进一步优化选择重要的特征。

优点:准确率高。
缺点:为选择出性能最好的特征子集,Wrapper算法需要的计算量巨大;该方法所选择的特征子集依赖于具体学习机;容易产生“过适应”问题,推广性能较差。

递归特征消除法

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

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)

Embedded

嵌入式特征选择先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于过滤式方法,但是是通过训练来确定特征的优劣。

优点:相对于包裹式方法,不用将训练数据集分成训练集和测试集两部分,避免了为评估每一个特征子集对学习机所进行的从头开始的训练,可以快速地得到最佳特征子集,是一种高效的特征选择方法。

缺点:构造一个合适的函数优化模型是该方法的难点。


基于惩罚项的特征选择法

使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维。

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)

实际上,L1惩罚项降维的原理在于保留多个对目标值具有同等相关性的特征中的一个,所以没选到的特征不代表不重要。故,可结合L2惩罚项来优化。具体操作为:若一个特征在L1中的权值为1,选择在L2中权值差别不大且在L1中权值为0的特征构成同类集合,将这一集合中的特征平分L1中的权值,故需要构建一个新的逻辑回归模型:

from sklearn.linear_model import LogisticRegression

class LR(LogisticRegression):
    def __init__(self, threshold=0.01, dual=False, tol=1e-4, C=1.0,
                 fit_intercept=True, intercept_scaling=1, class_weight=None,
                 random_state=None, solver='liblinear', max_iter=100,
                 multi_class='ovr', verbose=0, warm_start=False, n_jobs=1):

        #权值相近的阈值
        self.threshold = threshold
        LogisticRegression.__init__(self, penalty='l1', dual=dual, tol=tol, C=C,
                 fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight=class_weight,
                 random_state=random_state, solver=solver, max_iter=max_iter,
                 multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)
        #使用同样的参数创建L2逻辑回归
        self.l2 = LogisticRegression(penalty='l2', dual=dual, tol=tol, C=C, fit_intercept=fit_intercept, intercept_scaling=intercept_scaling, class_weight = class_weight, random_state=random_state, solver=solver, max_iter=max_iter, multi_class=multi_class, verbose=verbose, warm_start=warm_start, n_jobs=n_jobs)

    def fit(self, X, y, sample_weight=None):
        #训练L1逻辑回归
        super(LR, self).fit(X, y, sample_weight=sample_weight)
        self.coef_old_ = self.coef_.copy()
        #训练L2逻辑回归
        self.l2.fit(X, y, sample_weight=sample_weight)

        cntOfRow, cntOfCol = self.coef_.shape
        #权值系数矩阵的行数对应目标值的种类数目
        for i in range(cntOfRow):
            for j in range(cntOfCol):
                coef = self.coef_[i][j]
                #L1逻辑回归的权值系数不为0
                if coef != 0:
                    idx = [j]
                    #对应在L2逻辑回归中的权值系数
                    coef1 = self.l2.coef_[i][j]
                    for k in range(cntOfCol):
                        coef2 = self.l2.coef_[i][k]
                        #在L2逻辑回归中,权值系数之差小于设定的阈值,且在L1中对应的权值为0
                        if abs(coef1-coef2) < self.threshold and j != k and self.coef_[i][k] == 0:
                            idx.append(k)
                    #计算这一类特征的权值系数均值
                    mean = coef / len(idx)
                    self.coef_[i][idx] = mean
        return self

使用feature_selection库的SelectFromModel类结合带L1以及L2惩罚项的逻辑回归模型,来选择特征的代码如下:

from sklearn.feature_selection import SelectFromModel
 
#带L1和L2惩罚项的逻辑回归作为基模型的特征选择
#参数threshold为权值系数之差的阈值
SelectFromModel(LR(threshold=0.5, C=0.1)).fit_transform(iris.data, iris.target)
基于树模型的特征选择法

树模型中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)

降维

PCA是为了让映射后的样本具有最大的发散性;而LDA是为了让映射后的样本有最好的分类性能

主成分分析法(PCA)

from sklearn.decomposition import PCA

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

线性判别分析法(LDA)

from sklearn.lda import LDA

#线性判别分析法,返回降维后的数据
#参数n_components为降维后的维数
LDA(n_components=2).fit_transform(iris.data, iris.target)

神盾推荐系统特征工程模块


特征工程主要功能模块划分,主要是从特征类型上进行划分,单特征主要包括特征分析、特征组合、特征评估;多特征包括特征选择;衍生特征:特征构造,主要是用过现有特征,通过模型学习的方式生成新特征。

1、单特征(特征报告)

  • 归一化
  • 平滑
  • 离散化
  • 覆盖度
  • 缺失值
  • 单特征 AUC
  • 特征与目标值相关系数
  • KL 散度
  • 基尼系数

2、多特征(特征选择)

  • 卡方检验
  • 信息增益:互信息
  • 正则化
  • PCA
  • LDA

3、衍生特征(特征生成)

  • 基于 item 的 LR 模型
  • 相似度衡量模型,word2vec、LDA、热传导
  • GBDT
  • 深度学习:CNN、RNN
特征工程图谱

参考资料:
城东
特征工程方法综述

你可能感兴趣的:(python 特征工程 概述)