本篇笔记内容摘要:
特征工程的基础介绍和常用方法总结,包括对数转换、特征标准化、离散化、Label Encoder、OneHot Encoder 以及 Dummy Variables。
这系列文章大纲是基于 A Comprehensive Guide to Data Exploration 翻译搬运过来。作者在文章中比较系统地概括了EDA的内容,十分适合初学者学习。除了原作者的内容,我还整合了自己的学习笔记、以及网上找到的学习资料。
下面是之前的文章链接:
《探索性数据分析(1)—— 变量识别和分析》
《探索性数据分析(2)—— 缺失值处理》
《探索性数据分析(3)—— 异常值处理》
有任何翻译错误或内容补充,欢迎大家在评论区留言指出,欢迎一起讨论~
什么是特征工程?
特征工程就是从现有数据中提取更多信息。没有在原始数据里添加任何信息,但实际上特征工程可以使得原有的数据更加有用。找出在数据里的隐藏信息,这种从数据中提取信息的过程称为特征工程。
广义上说,特征工程也包含了数据清洗和预处理,只要是给数据加工并提纯出信息的,都可以算是特征工程
特征工程的流程是什么?
变量转换(Variable transformation )和特征构造(Variable / Feature creation.)是两个基本的流程。
在数据建模中,转换是指用函数替换变量。例如,将变量x替换为平方根/立方根或对数x就是一种转换。换言之,转换是一个改变变量与其他变量的分布或关系的过程。
什么时候需要变量转换?
当变量的单位、大小、分布等等不一致或者不方便我们分析,就需特征转换:
情况 | 处理方法 |
---|---|
1) 更改变量的比例或/标准化变量的值 | 对数转换、标准化/归一化 |
2) 将复杂的非线性关系转换为线性关系 | 对数转换、标准化/归一化 |
3)将斜分布转换为正态分布/对称分布(右偏) | 取变量的平方根/立方根或对数 |
4) 将斜分布转换为正态分布/对称分布(左偏) | 取变量的平方/立方或指数 |
5) 按业务经验需要转换变量 | 使用Binning按需要分组 |
对数变量是一种常用的转换方法,
变量的平方、立方、平方根、立方根、指数函数也是用于改变变量的分布。然而,它没有对数变换那么重要。
使用时注意原始数值范围是否小于1/-1,则平方和平方根的作用相反。例如 0. 5 2 = 0.25 \ 0.5^{2} = 0.25\, 0.52=0.25。
用于对变量进行分类,可以直接对变量原始值、百分比或频率执行。
一般是根据经验选择适合的分类区间。例如:把收入分成高、中、低三类;把学历分成高学历(大学、研究生、博士)和低学历(初中、高中)。
或者直接按分位数来划分区间,将数据分成几等份。
什么时候需要特征标准化
标准化主要是针对数值特征,将杂乱的数据整理好,更便于分析建模。
比如:特征数量级不一致。比如特征A是以万为单位(9W、6W、15W), 而特征B在[0-100]的区间里,两个特征大小不一致就会影响算法的结果。比如逻辑回归、KNN、聚类等距离计算。
特征缩放经验:
如果特性不是高斯型的,例如,有一个倾斜分布或有异常值,我们可以将特征转换为高斯类(用对数/平方/立方),然后使用规范化-标准化。
其他归一化方法:
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler, MaxAbsScaler
import numpy as np
import pandas as pd
np.set_printoptions(suppress=True)
#导入数据
views = pd.DataFrame([-100,-1000,1295., 25., 19000., 5., 1., 300.], columns=['views'])
#z-score标准化
views['zscore'] = StandardScaler().fit_transform(views[['views']])
#归一化-Minmax
views['minmax'] = MinMaxScaler().fit_transform(views[['views']])
#归一化-Maxabs
views['Maxabs']=MaxAbsScaler().fit_transform(views[['views']])
#Robust Scaling
views['robust'] = RobustScaler().fit_transform(views[['views']])
#查看结果
views
归一化和标准化的区别: 参考文章链接
为什么要离散化
通过将具有相似预测能力的相似属性分组,帮助提高模型性能。离散化的特征相对于连续型特征更易理解,大大降低异常值的影响,降低过拟合。
我自己的理解是:将一个范围内的连续性特征,也就是一堆数字,转换成了几个特定的分组。比如月收入0到100W,直接转换成低、中、高收入三组,使用三个类别替代了具体的收入数值,这样更容易理解,也减少了算法的时间。同时也排出了大部分异常值的干扰,像是超高收入的1000W也直接归类到了‘高收入’组里。
一般情况下,离散化方法没有最佳选择,主要取决于特征的含义和使用的算法。常见的方法有:
接着用上面的views数据,这里用最简单的离散化方法binning特征:
#自定义范围分组
bins=[-2000,0,2000,20000] #这个数要自己定
group=['小于0','2000以下','大于2000'] #标签名字
views['bin_labels'] =pd.cut(views['views'],bins,labels=group) #打标签
#分为数切分
quantile_list = [0, .25, .5, .75, 1.] #找出5个切分点
quantiles = views['views'].quantile(quantile_list) #找到具体切分的数字
quantile_labels = ['0-25Q', '25-50Q', '50-75Q', '75-100Q'] #标签值
views['viewslabels'] = pd.qcut(views['views'],q=quantile_list,labels=quantile_labels) #打标签分组
views
将分类变量每一种类别都转换为一种数字格式。
Data = pd.DataFrame(['红', '橙', '黄', '绿', '青', '绿','绿' ,'红'], columns=['A'])
#方法一:LabelEncoder
from sklearn.preprocessing import LabelEncoder
Data['A_labels'] = LabelEncoder().fit_transform(Data['A'])
#查看LabelEncoder具体标签
gle = LabelEncoder()
genre_labels = gle.fit_transform(Data['A'])# 将要转换的离散值的那一列传进来
genre_mappings = {index: label for index, label in enumerate(gle.classes_)}
genre_mappings
#方法二:用map操作, 自定数字标签
gen_ord_map = {'红': 1, '橙': 2, '黄': 3, '绿': 4, '青': 5} #自己写个字典
Data['A_map'] = Data['A'] .map(gen_ord_map) # 用map对目标离散值进行操作
#查看结果
Data
将离散型特征的每一种取值都看成一种状态,比如上面的例子,颜色中有5种状态:红橙黄绿青。1表示状态激活,0表示没有激活,则红色为:01000
注:数字从0开始,顺序为{0: ‘橙’, 1: ‘红’, 2: ‘绿’, 3: ‘青’, 4: ‘黄’}
A= OneHotEncoder().fit_transform(Data[['A']]).toarray()
A
什么是特征构造?
是基于现有变量生成新特征的过程。例如,我们在数据集中使用日期(dd-mm-yy)作为输入变量。我们可以生成新的变量,如日、月、年、周等等。
这是指使用一组函数或不同的方法从现有变量中创建新变量。
比如,在泰坦尼克号项目中,变量age有缺失值。为了预测处理缺失值,我们可以使用称呼(Master,Mr,Miss,Mrs)作为一个新变量,再计算不同称呼的平均年龄,根据称呼这个变量,对Age的缺失值进行插补。又比如,之前提及的对时间特征的信息提取,这又是另外一个重点问题了,这里先不多写。
如何决定要创建哪个变量?
这取决于分析师对业务的理解以及他对问题的一套假设。也可以使用记录变量、分块变量和其他变量转换方法来创建新的变量。
虚拟变量,也叫哑变量。创建虚拟变量的过程,有时也叫特征的Dummy化。
在统计模型中,将分类变量作为预测因子是很有用的。分类变量的值可以是0和1。让我们以一个变量“性别”为例。我们可以产生两个变量,即值为1(男性)和0(无男性)的“Var_男性”和值为1(女性)和0(无女性)的“Var_女性”。我们还可以为两个以上的类别变量创建虚拟变量,其中包含n个或n-1个虚拟变量。
OneHot Encoder 和 Dummy Variables 的区别:
OneHot N个特征 | Dummy(N-1)个特征 |
---|---|
OneHot和Dummy的区别:参考文章链接
#对数转换
train['要转换的那列数']=np.log(train['要转换的那列数'])
#Bin
#自定义范围分组
bins=[-2000,0,2000,20000] #这个数要自己定
group=['小于0','2000以下','大于2000'] #标签名字
views['bin_labels'] =pd.cut(views['views'],bins,labels=group) #打标签
#分为数切分
quantile_list = [0, .25, .5, .75, 1.] #找出5个切分点
quantiles = views['views'].quantile(quantile_list) #找到具体切分的数字
quantile_labels = ['0-25Q', '25-50Q', '50-75Q', '75-100Q'] #标签名
views['viewslabels'] = pd.qcut(views['views'],q=quantile_list,labels=quantile_labels) #打标签分组
#LabelEncoder
Data['A_labels'] = LabelEncoder().fit_transform(Data['A'])
#OneHot
A= OneHotEncoder().fit_transform(Data[['A']]).toarray()
#Dummy
pd.get_dummies(Data['color']) #对指定变量dummy化,
pd.get_dummies(Data) #对数据集中所有变量
##Dummy其他参数
pd.get_dummies(Data['color'],drop_first= True,prefix_sep = '——',prefix = '列名前缀') #drop_first是否要删掉第一维数据,prefix_sep是指定分隔符号
参考链接:
A Comprehensive Guide to Data Exploration
OneHot和Dummy的区别
归一化和标准化的区别