# 手把手教你入门和实践特征工程的全方位笔记，附代码下载

03 特征构建

#### 基础操作

# 本次案例使用的数据集

import pandas as pd

Xpd . DataFrame ({ ‘city’ :[ ‘tokyo’ , None , ‘london’ , ‘seattle’ , ‘san fancisco’ , ‘tokyo’ ],

‘boolean’ :[ ‘y’ , ‘n’ , None , ‘n’ , ‘n’ , ‘y’ ],

‘ordinal_column’ :[ ‘somewhat like’ , ‘like’ , ‘somewhat like’ , ‘like’ , ‘somewhat like’ , ‘dislike’ ],

‘quantitative_column’ :[ 1 , 11 , .5 , 10 , None , 20 ]})

X

# 填充分类变量（基于TransformerMixin的自定义填充器，用众数填充）

from sklearn . base import TransformerMixin

class CustomCategoryzImputer ( TransformerMixin ):

def __init__ ( selfcols = None ):

self . colscols

def transform ( selfdf ):

Xdf . copy ()

for col in self . cols :

X [ col ]. fillna ( X [ col ]. value_counts (). index [ 0 ],  inplace = True )

return X

def fit ( self* _ ):

return self

# 调用自定义的填充器

cciCustomCategoryzImputer ( cols =[ ‘city’ , ‘boolean’ ])

cci . fit_transform ( X )

# 填充分类变量（基于Imputer的自定义填充器，用众数填充）

from sklearn . preprocessing import Imputer

class CustomQuantitativeImputer ( TransformerMixin ):

def __init__ ( selfcols = Nonestrategy = ‘mean’ ):

self . colscols

self . strategystrategy

def transform ( selfdf ):

Xdf . copy ()

imputeImputer ( strategy = self . strategy )

for col in self . cols :

X [ col ] =  impute . fit_transform ( X [[ col ]])

return X

def fit ( self* _ ):

return self

# 调用自定义的填充器

cqiCustomQuantitativeImputer ( cols = [ ‘quantitative_column’ ],  strategy = ‘mean’ )

cqi . fit_transform ( X )

# 全部填充

from sklearn . pipeline import Pipeline

imputerPipeline ([( ‘quant’ , cqi ),

( ‘category’ , cci )

])

imputer . fit_transform ( X )

1）独热编码

# 类别变量的编码（独热编码）

class CustomDummifier ( TransformerMixin ):

def __init__ ( selfcols = None ):

self . colscols

def transform ( selfX ):

return pd . get_dummies ( Xcolumns = self . cols )

def fit ( self* _ ):

return self

# 调用自定义的填充器

cdCustomDummifier ( cols =[ ‘boolean’ , ‘city’ ])

cd . fit_transform ( X )

2）标签编码

# 类别变量的编码（标签编码）

class CustomEncoder ( TransformerMixin ):

def __init__ ( selfcolordering = None ):

self . orderingordering

self . colcol

def transform ( selfdf ):

Xdf . copy ()

X [ self . col ] =  X [ self . col ]. map ( lambda xself . ordering . index ( x ))

return X

def fit ( self* _ ):

return self

# 调用自定义的填充器

ceCustomEncoder ( col = ‘ordinal_column’ordering =[ ‘dislike’ , ‘somewhat like’ , ‘like’ ])

ce . fit_transform ( X )

3）数值变量分箱操作

# 数值变量处理——cut函数

class CustomCutter ( TransformerMixin ):

def __init__ ( selfcolbinslabels = False ):

self . labelslabels

self . binsbins

self . colcol

def transform ( selfdf ):

Xdf . copy ()

X [ self . col ] =  pd . cut ( X [ self . col ],  bins = self . binslabels = self . labels )

return X

def fit ( self* _ ):

return self

# 调用自定义的填充器

ccCustomCutter ( col = ‘quantitative_column’bins = 3 )

cc . fit_transform ( X )

1）用imputer填充缺失值

2）独热编码city和boolean

3）标签编码ordinal_column

4）分箱处理quantitative_column

from sklearn . pipeline import Pipeline

# 流水线封装

pipePipeline ([( ‘imputer’ , imputer ),

( ‘dummify’ , cd ),

( ‘encode’ , ce ),

( ‘cut’ , cc )

])

# 训练流水线

pipe . fit ( X )

# 转换流水线

pipe . transform ( X )

#### 数值变量扩展

# 人体胸部加速度数据集,标签activity的数值为1-7

”’

1-在电脑前工作

2-站立、走路和上下楼梯

3-站立

4-走路

5-上下楼梯

6-与人边走边聊

7-站立着说话

”’

df . columns = [ ‘index’ , ‘x’ , ‘y’ , ‘z’ , ‘activity’ ]

# 扩展数值特征

from sklearn . preprocessing import PolynomialFeatures

xdf [[ ‘x’ , ‘y’ , ‘z’ ]]

ydf [ ‘activity’ ]

polyPolynomialFeatures ( degree = 2include_bias = Falseinteraction_only = False )

x_polypoly . fit_transform ( x )

pd . DataFrame ( x_polycolumns = poly . get_feature_names ()). head ()

# 查看热力图(颜色越深代表相关性越强)

% matplotlib inline

import seaborn as sns

sns . heatmap ( pd . DataFrame ( x_polycolumns = poly . get_feature_names ()). corr ())

# 导入相关库

from sklearn . neighbors import KNeighborsClassifier

from sklearn . model_selection import GridSearchCV

from sklearn . pipeline import Pipeline

knnKNeighborsClassifier ()

# 在流水线中使用

pipe_params = { ‘poly_features__degree’ :[ 1 , 2 , 3 ],

‘poly_features__interaction_only’ :[ True , False ],

‘classify__n_neighbors’ :[ 3 , 4 , 5 , 6 ]}

# 实例化流水线

pipePipeline ([( ‘poly_features’ , poly ),

( ‘classify’ , knn )])

# 网格搜索

gridGridSearchCV ( pipepipe_params )

grid . fit ( x , y )

print ( grid . best_score_grid . best_params_ )

0.721189408065 {‘classify__n_neighbors’: 5, ‘poly_features__degree’: 2, ‘poly_features__interaction_only’: True}

#### 文本变量处理

1）bag of words

2）CountVectorizer

3）TF-IDF

TF-IDF向量化器由两个部分组成，分别为代表词频的TF部分，以及代表逆文档频率的IDF，这个TF-IDF是一个用于信息检索和聚类的词加权方法，在 sklearn.feature_extraction.text 中调用 TfidfVectorizer 即可。

TF：即Term Frequency，词频，也就是单词在文档中出现的频率。

IDF：即Inverse Document Frequency，逆文档频率，用于衡量单词的重要度，如果单词在多份文档中出现，就会被降低权重。

04 特征选择

from sklearn . model_selection import GridSearchCV

def get_best_model_and_accuracy ( modelparamsxy ):

gridGridSearchCV ( model ,

params ,

error_score = 0. )

grid . fit ( x , y )

# 经典的性能指标

print ( “Best Accuracy:{}” . format ( grid . best_score_ ))

# 得到最佳准确率的最佳参数

print ( “Best Parameters:{}” . format ( grid . best_params_ ))

# 拟合的平均时间

print ( “Average Time to Fit (s):{}” . format ( round ( grid . cv_results_ [ ‘mean_fit_time’ ]. mean (),  3 )))

# 预测的平均时间

print ( “Average Time to Score (s):{}” . format ( round ( grid . cv_results_ [ ‘mean_score_time’ ]. mean (),  3 )))

############### 使用示例 ###############

# 导入相关库

from sklearn . neighbors import KNeighborsClassifier

from sklearn . model_selection import GridSearchCV

from sklearn . pipeline import Pipeline

knnKNeighborsClassifier ()

# 在流水线中使用

pipe_params = { ‘poly_features__degree’ :[ 1 , 2 , 3 ],

‘poly_features__interaction_only’ :[ True , False ],

‘classify__n_neighbors’ :[ 3 , 4 , 5 , 6 ]}

# 实例化流水线

pipePipeline ([( ‘poly_features’ , poly ),

( ‘classify’ , knn )])

# 网格搜索

get_best_model_and_accuracy ( pipepipe_paramsxy )

#### 1）基于统计的特征选择

（1）皮尔逊相关系数可以通过 corr() 来实现，返回的值在-1到1之间，绝对值越大代表相关性越强；

（2）假设检验也就是p值，作为一种统计检验，在特征选择中，假设测试得原则是： 特征与响应变量没有关系 （零假设）为真还是假。我们需要对每个变量进行检测，检测其与target有没有显著关系。可以使用 SelectKBestf_classif 来实现。一般P值是 介于0-1 之间，简而言之， p值越小，拒绝零假设的概率就越大，也就是这个特征与target关系更大

#### 2）基于模型的特征选择

（1）对于文本特征， sklearn.feature_extraction.text 里的 CountVectorizer 有自带的特征筛选的参数，分别是 max_features、min_df、max_df、stop_words ，可以通过搜索这些参数来进行特征选择，可以结合 SelectKBest 来实现流水线。

（2）针对:evergreen_tree:树模型，我们可以直接调用不同树模型算法里的 特征重要度 来返回特征重要度，比如 DecisionTreeClassifier里的 feature_importances_ ，（除此之外还有RandomForest、GBDT、XGBoost、ExtraTreesClassifier等等）都可以直接返回每个特征对于本次拟合的重要度，从而我们可以剔除重要度偏低的特征，可以结合 SelectFromModel 来实现流水线。

（3）使用正则化来筛选变量（针对线性模型）。有两种常用的正则化方法： L1正则化（Lasso）和L2正则化（岭）。

#### 总结一下，有几点做特征选择的方法经验：

（1）如果特征是分类变量，那么可以从SelectKBest开始，用卡方或者基于树的选择器来选择变量；

（2）如果特征是定量变量，可以直接用线性模型和基于相关性的选择器来选择变量；

（3）如果是二分类问题，可以考虑使用 SelectFromModel和SVC；

（4）在进行特征选择前，还是需要做一下EDA。

05 特征转换

#### PCA：

PCA，即主成分分析（Principal Components Analysis），是比较常见的数据压缩的办法，即将多个相关特征的数据集投影到相关特征较少的坐标系上。也就是说，转换后的特征，在解释性上就走不通了，因为你无法解释这个新变量到底具有什么业务逻辑了。

PCA的原理这里就不展开来讲了，太多的文章把它讲得十分透彻了。这里主要是复现一下PCA在sklearn上的调用方法，一来继续熟悉下Pipeline的使用，二来理解一下PCA的使用方法。

# 导入相关库

from sklearn . datasets import load_iris

import matplotlib . pyplot as plt

% matplotlib inline

from sklearn . decomposition import PCA

# 导入数据集

iris_xiris_yiris . datairis . target

# 实例化方法

pcaPCA ( n_components = 2 )

# 训练方法

pca . fit ( iris_x )

pca . transform ( iris_x )[: 5 ,]

# 自定义一个可视化的方法

label_dict = { i : k for i , k in enumerate ( iris . target_names )}

def plot ( x , y , title , x_label , y_label ):

axplt . subplot ( 111 )

for label , marker , color in zip (

range ( 3 ),( ‘^’ , ‘s’ , ‘o’ ),( ‘blue’ , ‘red’ , ‘green’ )):

plt . scatter ( x = x [:, 0 ]. real [ y ==  label ],

yx [:, 1 ]. real [ y ==  label ],

colorcolor ,

alpha0.5 ,

labellabel_dict [ label ]

)

plt . xlabel ( x_label )

plt . ylabel ( y_label )

legplt . legend ( loc = ‘upper right’fancybox = True )

leg . get_frame (). set_alpha ( 0.5 )

plt . title ( title )

# 可视化

plot ( iris_xiris_y , “original iris data” , “sepal length(cm)” , “sepal width(cm)” )

plt . show ()

plot ( pca . transform ( iris_x ),  iris_y , “Iris: Data projected onto first two PCA components” , “PCA1” , “PCA2” )

#### LDA：

LDA，即线性判别分析（Linear Discriminant Analysis），它是一个有监督的算法（哦对了, PCA是无监督的），一般是用于分类流水线的预处理步骤。与PCA类似，LDA也是提取出一个新的坐标轴，将原始的高维数据投影到低维空间去，而区别在于LDA不会去专注数据之间的方差大小，而是直接优化低维空间，以获得最佳的类别可分性。

# LDA的使用

# 导入相关库

from sklearn . discriminant_analysis import LinearDiscriminantAnalysis

# 实例化LDA模块

ldaLinearDiscriminantAnalysis ( n_components = 2 )

# 训练数据

x_lda_irislda . fit_transform ( iris_xiris_y )

# 可视化

plot ( x_lda_irisiris_y“LDA Projection”“LDA1”“LDA2” )

06 特征学习

#### 受限玻尔兹曼机（RBM）

RBM是一种简单的深度学习架构，是一组无监督的特征学习算法，根据数据的概率模型学习一定数量的新特征，往往使用RBM之后去用线性模型（线性回归、逻辑回归、感知机等）的效果极佳。

“受限”的说法是因为它只允许层与层之间的连接（层间连接），而不允许同一层内的节点连接（层内连接）。

# RBM的使用

# 我们使用MNIST数据集来讲解

# 导入相关库

import numpy as np

import matplotlib . pyplot as plt

% matplotlib inline

from sklearn . linear_model import LogisticRegression

from sklearn . neural_network import BernoulliRBM

from sklearn . pipeline import Pipeline

# 导入数据集

imagesnp . genfromtxt ( ‘./data/mnist_train.csv’delimiter = ‘,’ )

print ( images . shape )

# 划分数据

images_ximages_yimages [:, 1 :],  images [:, 0 ]

# 缩放特征到0-1

images_ximages_x / 255.

# 用RBM学习新特征

rbmBernoulliRBM ( random_state = 0 )

lrLogisticRegression ()

# 设置流水线的参数范围

params = { ‘clf__C’ :[ 1e-11e01e1 ],

‘rbm__n_components’ :[ 100200 ]

}

# 创建流水线

pipelinePipeline ([( ‘rbm’rbm ),

( ‘clf’lr )])

# 实例化网格搜索类

gridGridSearchCV ( pipelineparams )

# 拟合数据

grid . fit ( images_ximages_y )

# 返回最佳参数

grid . best_params_grid . best_score_