书接上文,本篇接下来将介绍特征变换的内容。
核心思想:将一组特征转换成可用数字表示、形式统一并且包含较可能多原始信息的新特征。一般包括对指化、离散化、归一化、数值化、正规化(规范化)等方法。
(1)指数化(numpy.exp())
对数据指数化可以将数据间的差异放大,当我们想直观看到数据之间的大小时可以用指数化。
(2)对数化(numpy.log())
平时在一些数据处理中,经常会把原始数据取对数后进一步处理。之所以这样做是基于对数函数在其定义域内是单调增函数,取对数后不会改变数据的相对关系,取对数作用主要有:
所谓的离散化就是将无限空间中的有限个体映射到有限空间中,以便于研究个体属性。离散化大多是针对连续数据进行的,经过处理之后的数据分布将会从连续属性变为离散属性。为了克服数据缺陷(如存在异常状态的数据),增强模型的准确度和稳定性,以及应某些算法的要求(如朴素贝叶斯),就需要对数据进行离散化。例如对于下面存在一个拐点的一个数据集,我们可以将函数按照位于2000的拐点分左右两段来进行分析,这样分析会更加贴合实际,增加模型的适用性。
常用的离散化方法一般有等频、等距、自因变量优化3种方法,核心思想就是将连续数据排序后分为特定区间的集合这个过程也叫作分箱,就是把数据分在一个个集合箱子里装好。划分方法依据数据类型和探究目的不同而有所变化,例如年龄数据就可以按照(<10)(10-50)(50-90)(>90)划分不同区间。
(1)等频(等深) 分箱
n表示数据的个数,a表示集合(箱)的个数。
假设[13,26,10,88,75,48,39,91,28]是我们搜集到的年龄数据,现在我们将年龄分为三个箱,并用['low age','medium age','high age']命名。
import numpy as np
import pandas as pd
lst=[13,26,10,88,75,48,39,91,28]
lst.sort() #记得对数据进行排序
lst
pd.qcut(lst,q=3,labels=['low age','medium age','high age'])
以上就是等深分箱的结果,前三个为Low age,中间三个为mediumage,最后三个为high age。
(2)等距(等宽)分箱
即用数据的最大值减去最小值后除以要分的箱个数。
以上面的年龄数据为例。
pd.cut(lst,bins=3,labels=['low age','medium age','high age'])
这时将前面四条数据视为low age,中间两条为medium age,最后三条为high age。
(3)自因变量优化
自因变量优化的方法是根据数据分布的特点,找到拐点等特殊点作为分箱的依据。
在我们获得原始数据集中,不同的评价指标会产生不同的来那个量纲。如果不做处理的话就会对数据分析的结果产生较大的影响,往往得到的结果可信度不会太高。为了消除量纲带来的影响,就需要对数据进行归一化(标准化)处理,使数据之间处于同一量级并具有可比性。
(1)最大最小标准化
又称为离差标准化,使结果映射到[0,1]之间,比较适用在数值比较集中的情况。公式如下:
从上面式子可以看出,如果max和min不稳定,很容易使得归一化结果不稳定,使得后续使用效果也不稳定。实际使用中可以用经验常量来替代max和min,代码如下:
from sklearn.preprocessing import MinMaxScaler
MinMaxScaler().fit_transform(np.array([1,4,10,15,21]).reshape(-1,1))
#reshape(-1,1)表示将前面的数组转成行数不定,列数为1的数据
(2)Z-Score标准化
数据经过处理后为标准正态分布,均值为0, 标准差为1,转换公式为:
本方法要求原始数据的分布可以近似为正态分布,否则归一化的效果会变得很糟糕。
from sklearn.preprocessing import StandardScaler
StandardScaler().fit_transform(np.array([1,1,1,1,0,0,0,0]).reshape(-1,1))
在原始数据集中,数据的类型是多种多样的,为了方便分析,我们需要将文本类型的数据数字化以进行数据分析。数值化处理主要是针对定类数据和定序数据的处理,其中用标签法处理定序数据,用独热法(OneHot)处理定类数据。
(1)标签法(Label)
标签法主要用来将定序数据数值化,定序数据指的是数据之间有大小,但不能测定差值的一类数据。比如工资水平可以分为低工资、中等工资、高工资,他们之间存在大小关系,但不能计算差值。此时饿哦们保留大小信息就足够了,不用在乎差值有多大,将这三个水平分别用0、1、2表示。代码如下:
from sklearn.preprocessing import LabelEncoder
LabelEncoder().fit_transform(np.array(['low','medium','medium','medium','high','low','low','medium','high']).reshape(-1,1))
值得注意的是,这个标签函数是根据数据的首字母的顺序来为其赋值的,h在l、m前面,所以被赋为了最小值。我们可以通过创建字典来人为的为数据赋值。代码如下:
lst1=np.array(['low','medium','medium','medium','high','low','low','medium','high'])
d=dict([('low',0),('medium',1),('high',2)])
def map_salary(s):
return d.get(s,0) #设定默认值为0
lst1_oh=[map_salary(s) for s in lst1]
lst1_oh
bingo,得到我们想要的结果啦。
(2)独热法(OneHot)
独热法(OneHot)主要用来将定类数据数值化,定类数据是根据事物离散、无差别属性进行的数据分类。比如一个颜色特征数据,其数据内容为红色、黄色、绿色、白色、黑色,数据之间地位平等,没有大小关系,也无差值。经过独热法处理,我们可以将原内容转化成以下形式(按首字母排序):
这样就很好的处理了分类数据的字符型问题,并且保留了数据的信息。以下我们用独热法为['red','yellow','green','white','black','yellow','green','white','red','yellow','green','white','black','yellow','green']进行赋值,代码和结果见下:
from sklearn.preprocessing import LabelEncoder,OneHotEncoder
lb_encoder=LabelEncoder()
#使用独热法之前需要将所有的数据分类进行标签化
#首先提取数据分类,也就是对分类数据去重
color_data=pd.DataFrame({'color':['red','yellow','green','white','black','yellow','green','white','red','yellow','green','white','black','yellow','green']})
color_dup=color_data.drop_duplicates(['color'])#删除重复数据
color_arr=np.array(color_dup)#去重后剩余5个颜色
lb_tran_f=lb_encoder.fit_transform(color_arr)#将数据进行标签化,赋值为0,1,2,3,4
lb_tran_f_r=lb_tran_f.reshape(-1,1) #reshape(-1,1)函数将数据转成1列,以达到OneHot要求
oht_encoder=OneHotEncoder().fit(lb_tran_f_r) #进行独热法转换
oht_encoder.transform(lb_encoder.transform(color_data).reshape(-1,1)) #进行独热法赋值,返回一个不可见的矩阵,要使矩阵可见,需在最后面加上.toarray()
oht_encoder.transform(lb_encoder.transform(color_data).reshape(-1,1)).toarray()
OneGotEncoder方法使用起来比较麻烦,在python中用get_dummies()函数也可以达到同样的效果,代码如下:
import pandas as pd
dum_data=pd.get_dummies(color_data,columns=['color'])
dum_data
本质:将一个向量的长度正规到单位1,这个思想与归一化的思想一样。
L1表示用每个特征的数据除以该特征的曼哈顿距离。
L2表示用每个特征的数据除以该特征的欧式距离。
代码如下:
from sklearn.preprocessing import Normalizer
Normalizer(norm='l1').fit_transform(np.array([[1,1,3,-1,2]]))
Normalizer(norm='l2').fit_transform(np.array([[1,1,3,-1,2]]))