「Python」sklearn第二弹-归一化和离散值编码
本文主要讲解sklearn里面的归一化,其中包括-L1范式和L2范式。 还讲解了关于离散值编码,主要涉及到的编码方式有LabelEncoder和OneHotEncoder。
先介绍一下归一化:
归一化
why? --- 加快训练速度 归一化是缩放单个样本以具有单位范数的过程。
归一化实质是一种线性变换,线性变换有很多良好的性质,这些性质决定了对数据改变后不会造成“失效”,反而能提高数据的表现,这些性质是归一化的前提。
归一化能够加快模型训练速度,统一特征量纲,避免数值太大。值得注意的是,
归一化是对每一个样本做转换,所以是对数据的每一行进行变换。而之前我们讲过的方法是对数据的每一列做变换。
L1范式
调用L1范式:
from sklearn.preprocessing import normalize
x = normalize(x,'l1')
L1范式定义:
向量x中每个元素的绝对值之和
公式表示:
∥x∥1=∑i=1n∣xi∣\begin{Vmatrix}x \end{Vmatrix}_1 = \sum_{i=1}^n |x_i| ∥∥∥x∥∥∥1=∑i=1n∣xi∣
L1范式归一化就是将样本中每个特征除以特征的L1范式。
通过normalize
实现:
from sklearn.preprocessing import normalize data = np.array([[-1,0,1], [1,0,1], [1,2,3]]) data = normalize(data,'l1') >>>data array([[-0.5 , 0. , 0.5 ], [ 0.5 , 0. , 0.5 ], [ 0.167, 0.333, 0.5 ]])
L2范式
x = normalize(x,'l2')
L2范式定义:
向量元素的平方和再开平方根
公式:
L2范式归一化就是将样本中每个特征除以特征的L2范式
from sklearn.preprocessing import normalize data = np.array([[-1,0,1], [1,0,1], [1,2,3]]) data = normalize(data,'l2') >>>data array([[-0.707, 0. , 0.707], [ 0.707, 0. , 0.707], [ 0.267, 0.535, 0.802]])
离散值编码
离散值特征变量可以分为有序类和无序类。
无序类:价值相等且可区分,各变量相互独立。如:性别(男/女)、颜色(红橙黄绿青蓝紫)
有序类:各变量有级别大小等逻辑关系。如:学历(高/中/低)、尺码(S/M/L/XL..)
为什么需要编码?
对无序类:不能直接对特征进行赋值,比如male-1, female-0。
这是不科学的,因为这样一来就存在了大小关系,在算法学习时就会利用其大小关系来训练和预测。任何两个数值如1和0,都无法表示出male与female的价值相等且可区分的平行独立的关系.
但改成这样就可以了:male-[0,1],female-[1,0]
对有序类:
比如学历变量是博士、硕士、本科,分别用3-2-1来表示。
那么问题来了:为何可以用3-2-1来表示而不能用30-20-10来表示?如果1000-900-800呢?
但事实却是任何数字的排序都无法表达出变量的差异性。
何时不需要编码?
编码的作用本来就是让特征之间的距离计算更加合理,但是如果特征是离散的,并且不用one-hot编码就可以很合理的计算出距离,那么就没有必要进行one-hot编码。(如Titanic中的age特征)
有些基于树的算法在处理变量时,并不是基于向量空间度量,数值只是个类别符号,即没有偏序关系,所以不用进行独热编码。如: Tree Model不太需要one-hot编码, 对于决策树来说,one-hot的本质是增加树的深度。
编码的方式大致有三种:
- LebelEncoder:适合处理字符型数据或者label类,一般先用此方法将字符型数据转化为数值型,然后再用get_dummies或OneHot编码。
- get_dummies:pandas方法,多适用于DataFrame数据
- OneHotEncoder:普遍的额编码方法
这里只简单的介绍一下第一种和第三种编码方式,请往下看:
LabelEncoder
在数据挖掘中,特征经常不是数值型的而是分类型的。
举个例子,一个人可能有["male", "female"],["from Europe", "from US", "from Asia"],["uses Firefox", "uses Chrome",
"uses Safari", "uses Internet Explorer"]等分类的特征。
这些特征能够被有效地编码成整数,
比如["male", "from US", "uses Internet Explorer"]可以被表示为[0, 1, 3],["female", "from Asia", "uses Chrome"]表示为[1, 2, 1]。
在sklearn中,通过LabelEncoder来实现:
from sklearn.preprocessing import LabelEncoder label = ['male','female'] int_label = LabelEncoder() label = int_label.fit_transform(label) >>>label array([1, 0])
OneHotEncoder
上面那种整数特征表示并不能在sklearn的估计器中直接使用,因为这样的连续输入,估计器会认为类别之间是有序的,但实际却是无序的。
如将male,female,转换为1,0。1比0要大,机器就会把这个关系考虑进去,而male,female之间是没有这样的关系的。
所以我们需要使用另外一种编码方式,OneHot编码。 在sklearn中通过OneHotEncoder来实现,使用方法如下:
import numpy as np from sklearn.preprocessing import OneHotEncoder label = np.array([1,0]) label = np.array(label).reshape(len(label),1) #先将X组织成(sample,feature)的格式 onehot_label = OneHotEncoder() label = onehot_label.fit_transform(label).toarray() >>>label array([[0., 1.], [1., 0.]])
在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间.
对离散型特征进行one-hot编码是为了让距离的计算显得更加合理。
编码后的特征会扩维(如性别编码后变成male-[0,1],female-[1,0]),这样数据会变得稀疏。
稀疏对算法来说是有好处的:
1.当某列的元素都为零时就意味着可以去除这个特征,则学习的难度、计算和存储开销都会降低;
2.即便每个样本中有很多零元素,但是都不不是以整列或整行存在的,这样依旧有好处。 比如支持向量机之所以能在文本数据上有很好的性能,就是由于数据有高度的稀疏性,使得大多数问题可以变得线性可分,而且稀疏矩阵有高效的存储方法,节约存储空间。