深度之眼比赛实战班第一场比赛作业1.5 | 摘录笔记

sklearn-feature-engineering(特征工程)

1. 什么是特征工程?

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已,特征工程的本质就是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。

特征工程主要分为三部分:

  1. 数据预处理 对应的sklearn包:sklearn-Processing data
  2. 特征选择对应的sklearn包: sklearn-Feature selection
  3. 降维 对应的sklearn包:sklearn-Dimensionality reduction

本文中使用sklearn中的RIS(鸢尾花)数据集来对特征处理能力进行说明,导入代码:

from sklearn.datasets import load_iris

# 导入IRIS数据集
iris = load_iris()

# 特征矩阵
iris.data

# 目标向量
iris.target

2. 数据预处理

通过特征提取,我们能得到未处理的特征,这时的特征可能有以下问题:

  • 不属于同一量纲:即特征的规格不一样,不能够放在一起比较。 无量纲化可以解决这一问题。
  • 信息冗余:对于某些定量特征,其包含的有效信息为区间划分,例如学习成绩,假若只关心"及格"或"不及格",那么需要将定量的考分,转换成"1"和"0"表示及格或未及格。二值化可以解决这一问题。
  • 定量特征不能直接使用:通常使用哑编码(One-hot)的方式将定性特征转换为定量特征,假设有N种定性值,则将一个特征扩展为N种特征,当原始特征值为第i种定性值时,第i个扩展特征赋值为1,其他扩展特征为0,哑编码的方式相比直接指定的方式,不用增加调参的工作,对于线性模型来说,使用哑编码后的特征可达到非线性的效果。
  • 存在缺失值:填充缺失值。
  • 信息利用率低:不同的机器学习算法和模型对数据中信息的利用是不同的,线性模型种,使用对定性特征哑编码可以达到非线性的效果,类似地,对定量变量多项式化,或者进行其他的数据变换,都能达到非线性的效果。

sklearn中的preprocessing库来进行数据预处理

2.1 无量纲化(数据规范化)

from sklearn.preprocessing import StandardScaler
std = StandardScaler()

# 标准化,返回值为标准化后的数据
std.fit_transform(iris.data)

# 标准化的特征目标向量(各种鸢尾花的名称)
std.fit_transform(iris.target.reshape(-1,1))

无量纲化使得不同规格的数据转换到同一规格

2.1.1 标准化(Z-score standardization)(对列向量进行处理)

将服从正太分布的特征值转换为标准正态分布,标准化需要计算特征的均值和标准差,一般公式为: x ′ = x − X ‾ S x' = \frac{x - \overline{X}}{S} x=SxX

使用preprocessing库的StandardScaler类对数据进行标准化的代码同上


2.1.2 区间缩放(对列向量处理)

区间缩放法的思路有多种,常见为最大最小值缩放,公式为:

x ′ = x − M i n M a x − M i n x' = \frac{x -Min}{Max - Min} x=MaxMinxMin

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

from sklearn.preprocessing import MinMaxScaler
# 区间缩放,返回值为缩放到[0,1]的数值
MinMaxScaler().fit_transfrom(iris.data)

处理后的值最大值为1最小值为0,其他值按比例缩放

什么时候用标准化,什么时候用区间缩放比较好

  1. 在后续的分类、聚类算法中,需要使用距离来度量相似性的时候,或者使用PCA,LDA这些需要用到协方差分析进行降维的时候,同时数据分布可以近似为正态分布,标准化方法表现更好(Z-score standardization)(标准化好一些)
  2. 在不涉及距离度量,协方差计算,数据不符合正态分布的时候,可以使用区间缩放法或者其他归一化方法。比如图像处理中,将RGB图像转换为灰度图像后将其值限定在[0,255]的范围。(归一化好点)

2.1.3 归一化(Normalize)(对行向量处理)

归一化得目的在于样本向量在点乘运算或其他核函数计算相似性时,拥有统一的标准,也就是说都转换为"单位向量"。L2的归一化公式如下:

x ′ = x ∑ j m x [ j ] 2 x' =\frac{x}{\sqrt{\sum_{j}^{m}x[j]^2}} x=jmx[j]2 x

使用preprocessing库的Normalizer类对数据进行归一化的代码如下:

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

标准化(StandardScaler)和归一化(Normalizer)

StandardScaler就是尺寸缩放,将同一特征下的数值在一定范围内浮动,如将数值缩放在0~1范围内(MinMaxScaler),或者将数据标准化,变成均值为0,方差为1的数据(Z-score);

Normalizer就是将同一行数据的不同特征进行规范化,这样一个数据的不同特征具有相同的量纲或者表现力,比如说一个特征是身高1.7m,体重为150kg,那么两个特征之间差距太大,身高这个特征变化根本无法起到决定作用(在体重这个变化特征下),毕竟大家怎么长都是一米多,但是体重差距一下子拉开20多是很正常的事情

2.2 对定量特征二值化(对列向量处理)

定性与定量的区别

定性:及格与不及格

定量:85分,39分

一般定性都会有相关的描述词,定量的描述一般都可以用数字量化处理

定量特征二值化的核心在于设定一个阈值,大于阈值的赋值为1,小于等于阈值的赋值为0

使用preprocessing库的Binarizer类对数据进行二值化的代码如下:

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

2.3 对定性特征哑编码(One-hot)(对列向量处理)

有些特征是用文字分类表达的,或者说将这些类转化为数字,但是数字与数字之间是没有大小关系的,纯粹的分类标记,这时候就需要用哑编码对其进行编码,IRIS数据集的特征皆为定量特征,使用其目标值进行哑编码(实际上是不需要的)。使用preprocessing库的OneHotEncoder类对数据进行哑编码的代码如下:

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

补充:但是从另一个角度来看,在标签需要被量化的时候就很有用了

2.4 缺失值计算(对列向量处理)

由于IRIS数据集没有缺失值,故对数据集新增一个样本,4个特征均赋值为NaN,表示数据缺失,使用preprocessing库的Imputer类对数据进行缺失值计算的代码如下:

import numpy as np
from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN',strategy='mean',axis=0) 	
# 使用特征值的均值进行填充,其余还有众数(median)填充等
data = np.array([np.nan,2,6,np.nan,7,6]).reshape(3,2)
imp.fit_transform(data)

2.5 数据变换

2.5.1 多项式变换(对行向量处理)

常见的数据变换有基于多项式的、基于指数函数的、基于对数函数的。4个特征,度为2的多项式转换公式如下:
(x1’,x2’,x3’,x4’,x5’.x6’,x7’,x8’,x9’,x10’,x11’.x12’,x13’,x14’.x15’)=(1,x1,x2,x3,x4, x12,x1*x2 , x1*x2 ,x1*x4 ,x22 ,x2 * x2,x2 * x4, x32 ,x3 * x4 ,x42)

使用preprocessing库的PolynomialFeatures类对数据进行多项式转换的代码如下:

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

2.5.2 自定义变换

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

from numpy import log1p # log(x+1)  
from sklearn.preprocessing import FunctionTransformer  
# 自定义转换函数为对数函数的数据变换  
# 第一个参数是单变元函数  
FunctionTransformer(log1p).fit_transform(iris.data)

2.6 总结

功能说明
StandardScaler无量纲化标准化,基于特征矩阵的列,将特征值转换至服从标准正态分布
MinMaxScaler无量纲化区间缩放,基于最大值最小值,将特征值转换到[0,1]区间上
Normalizer归一化基于特征矩阵的行,将样本向量转换为"单位向量"
Binarizer二值化基于给定阈值,将定量特征按阈值划分
OneHotEncoder哑编码将定性数据编码为定量数据
Imputer缺失值计算计算缺失值,缺失值可填充为均值等
PolynomialFeatures多项式数据转换多项式数据转换
FunctionTransformer自定义单元数据转换使用单变元的函数来转换数据

3. 特征选择

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

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

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

  • Filter : 过滤法,不用考虑后续学习器,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
  • Wrapper : 包装法,需考虑后续学习器,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
  • Embedded : 嵌入法,是Filter与Wrapper方法的结合。先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。

我们使用sklearn中的feature_selection库来进行特征选择

3.1 Filter(过滤法)

3.1.1 方差选择法

使用方差选择法,先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。使用feature_selection库的VarianceThreshold类来选择特征的代码如下:

from sklearn.feature_selection import VarianceThreshold
# 方差选择法,返回值为特征选择后的数据
# 参数threshold为方差的阈值,为几就是过滤掉几个特征
VarianceThreshold(threshold=3).fit_transform(iris.data)
3.1.2 单变量特征选择

单变量特征选择能够对每一个特征进行测试,衡量该特征和目标变量之间的关系,根据得分扔掉不好的特征。对于回归和分类问题可以采用卡方检验等方式对特征进行测试。

方法简单,易于运行,易于理解,通常对于理解数据有较好的效果。(但对特征优化、提高泛化能力来说不一定有效);方法有很多改进版本、变种。

3.1.2.1 卡方检验

chi2卡方检验:适用于分类问题,y离散

经典的卡方检验(原理及应用)是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量,其中A为实际数,E为理论值:
x 2 = ∑ ( A − E ) 2 E x^{2} = \sum{\frac{(A-E)^2}{E}} x2=E(AE)2

检验特征对标签的相关性,选择其中K个标签最相关的特征。使用feature_selection库的SelectKBest类结合卡方检验来选择特征的代码如下:(这个就是自变量与因变量的相关性的取值,看到k的取值)

from sklearn.feature_selection import SelectKBest,chi2
# chi2就是卡方检验
# 选择k个最好的特征,返回选择特征后的数据
SelectKBest(chi2,k=2).fit_transform(iris.data, iris.target)
3.1.2.2 pearson相关系数(pearson correlation)

pearson相关系数:适用于回归问题(y连续)

皮尔森相关系数是一种最简单的,能帮助理解特征和目标变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为[-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)
# ↑ 创建300个均值为0,方差为1的高斯随机数
# 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)
3.1.3 互信息和最大信息系数(MIC)

Mutual information and maximal information coefficient

后面讲EDA的时候再讲

3.1.4 距离相关系数(Distance Correlation)

距离相关系数是为了克服Peason相关系数的弱点而生的。在x和x2 这个例子中,即便pearson相关系数是0,我们也不能断定这两个变量是独立的(有可能是非线性相关的);但如果距离相关系数是0,那么我们可以说这两个变量是独立的。

​ R语言的energy包里提供了距离相关系数的实现,另外这是Python gist的实现

> x = runif(1000, -1, 1)
> dcor(x, x**2)
[1] 0.4943864

尽管有MIC和距离相关系数在,在变量之间的关系接近线性相关的时候,pearson相关系数仍然是不可替代的。

第一,pearson相关系数的计算速度快,在处理大规模数据的时候很重要

第二,pearson相关系数的取值区间是[-1, 1], 而MIC和距离相关系数都是[0, 1]。这个特点使得Pearson相关系数能够表征更丰富的关系,符号表示关系的正负,绝对值能够表示强度。当然pearson相关性有效的前提是两个变量的变化关系是单调的。

###3.2 Wrapper(包装法)

包装法的主要是思想是:根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征,也可以将特征子集的选择看作一个搜索寻优问题,生成不同的组合,对组合进行评价,再与其他的组合进行比较。这样就将自己的选择看作是一个优化问题。这里又很多的优化算法可以解决,尤其是一些启发式的优化算法,如GA,PSO,DE,ABC等。

3.2.1 递归特征消除法

递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练,使用feature_selection库的RFE来选择特征的代码如下:

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

# 递归特征消除法,返回特征选择后的数据
# 参数 estimator为基模型
# 参数 n_feature_to_select为选择的特征个数
RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)

3.3 Embedded(嵌入法)

嵌入法主要思想是:使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。其实是在确定模型的过程中,挑选出那些对模型的训练有重要意义的属性。

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

使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维,使用feature_selection库的SelectFromModel类结合带L1惩罚项的逻辑回归模型,来选择特征,代码如下:

from sklearn.feature_selection import SelectionFromModel
from sklearn,linear_model import LogisticRegression

# 带L1惩罚项的逻辑回归作为基模型的特征选择
SelectFromModel(LogisticRegression(penalty="l1", c=0.1)).fit_transform(iris.data, iris.target)

# 看一下例子,用的是支持向量机
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
iris = load_iris()
X, y = iris.data, iris.target
X.shape
# (150, 4)
lsvc = LinearSVC(0.01. penalty="l1", dual=False).fit(X, y)
model = SelectFromModel(lsvc, prefit=True)
X_new = model.transform(X)
X_new[:3,:]
#array([[ 5.1, 3.5, 1.4],
# [ 4.9, 3. , 1.4],
# [ 4.7, 3.2, 1.3]])

结合L2项下次看

3.3.2 基于树模型的特征选择法
from sklearn.feature_selection import SelectionFromModel
from sklearn.ensemble import GradientBoostingClassifier

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

3.4 总结

所属方式说明
VarianceThresholdFilter方差选择法
SelectKBestFilter可选关联系数、卡方校验、最大信息系数作为得分计算的方法
RFEWrapper递归地训练基模型,将权值系数较小的特征从特征集合中消除
SelectFromModelEmbedded训练基模型,选择权值系数较高的特征
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值