目录
一 OneHotEncoder独热编码
1.1 OneHotEncoder独热编码原理
2.1. 为什么要独热编码OneHotEncoder?
2.3 独热编码优缺点
2.4 什么情况下(不)用独热编码?
2.5 什么情况下(不)需要归一化?
二 Label Encoder标签编码
三、Binary Encoder二进制编码
首先了解机器学习中的特征类别:连续型特征和离散型特征
拿到获取的原始特征,必须对每一特征分别进行归一化,比如,特征A的取值范围是[-1000,1000],特征B的取值范围是[-1,1].如果使用logistic回归,w1*x1+w2*x2,因为x1的取值太大了,所以x2基本起不了作用。所以,必须进行特征的归一化,每个特征都单独进行归一化。
对于连续性特征:
有界连续特征:线性放缩到[-1,1]标准化所有连续特性: 放缩到均值为0,方差为1对于离散性特征:
二值化分类/离散特征:对于离散的特征基本就是按照one-hot(独热)编码,该离散特征有多少取值,就用多少维来表示该特征。
官方文档:点击就送
独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。举例如下:
假如有三种颜色特征:红、黄、蓝。 在利用机器学习的算法时一般需要进行向量化或者数字化。那么你可能想令 红=1,黄=2,蓝=3. 那么这样其实实现了标签编码,即给不同类别以标签。然而这意味着机器可能会学习到“红<黄<蓝”,但这并不是我们的让机器学习的本意,只是想让机器区分它们,并无大小比较之意。所以这时标签编码是不够的,需要进一步转换。因为有三种颜色状态,所以就有3个比特。即红色:1 0 0 ,黄色: 0 1 0,蓝色:0 0 1 。如此一来每两个向量之间的距离都是根号2,在向量空间距离都相等,所以这样不会出现偏序性,基本不会影响基于向量空间度量算法的效果。
自然状态码为:000,001,010,011,100,101
独热编码为:000001,000010,000100,001000,010000,100000
来一个sklearn的例子:
from sklearn import preprocessing enc = preprocessing.OneHotEncoder() enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]]) # fit来学习编码 enc.transform([[0, 1, 3]]).toarray() # 进行编码 array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])数据矩阵是4*3,即4个数据,3个特征维度。
观察上面的数据矩阵,第一列为第一个特征维度,有两种取值0\1. 所以对应编码方式为10 、01
同理,第二列为第二个特征维度,有三种取值0\1\2,所以对应编码方式为100、010、001
同理,第三列为第三个特征维度,有四中取值0\1\2\3,所以对应编码方式为1000、0100、0010、0001
再来看要进行编码的参数[0 , 1, 3], 0作为第一个特征编码为10, 1作为第二个特征编码为010, 3作为第三个特征编码为0001. 故此编码结果为 1 0 0 1 0 0 0 0 1
正如上文所言,独热编码是因为大部分算法是基于向量空间中的度量来进行计算的,为了使非偏序关系的变量取值不具有偏序性,并且到圆点是等距的。使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。离散特征进行one-hot编码后,编码后的特征,其实每一维度的特征都可以看做是连续的特征。就可以跟对连续型特征的归一化方法一样,对每一维特征进行归一化。比如归一化到[-1,1]或归一化到均值为0,方差为1。
为什么特征向量要映射到欧式空间?
将离散特征通过one-hot编码映射到欧式空间,是因为,在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间。
总的来说,要是one hot encoding的类别数目不太多,建议优先考虑。
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html#sklearn.preprocessing.LabelEncoder
sklearn.preprocessing.LabelEncoder():标准化标签,将标签值统一转换成range(标签值个数-1)范围内
标签编码通常用于处理类别间有大小关系的数据。例如成绩等,转换后依然保留了大小关系
将离散型的数据转换成0到n-1之间的数,这里的n是一个列表的不同取值的个数,可以认为是某个特征的所有不同取值的个数
例子:
from sklearn import preprocessing le = preprocessing.LabelEncoder() le.fit(["Japan", "china", "Japan", "Korea","china"]) print('标签个数:%s' % le.classes_) print('标签值标准化:%s' % le.transform(["Japan", "china", "Japan", "Korea","china"])) print('标准化标签值反转:%s' % le.inverse_transform([0, 2 ,0 ,1 ,2])) # 标签个数:['Japan' 'Korea' 'china'] # 标签值标准化:[0 2 0 1 2] # 标准化标签值反转:['Japan' 'china' 'Japan' 'Korea' 'china']
限制:上文颜色的例子已经提到标签编码了。Label encoding在某些情况下很有用,但是场景限制很多。再举一例:比如有[dog,cat,dog,mouse,cat],我们把其转换为[1,2,1,3,2]。这里就产生了一个奇怪的现象:dog和mouse的平均值是cat。所以目前还没有发现标签编码的广泛使用。
二进制编码主要分为2步,先用序号编码给每个类别赋予一个ID,然后ID对应的二进制代码作为结果,以A\B\AB\O血型为例
具体如下图
血型ID二进制表示独热编码A10 0 1 1 0 0 0B20 1 00 1 0 0AB30 1 10 0 1 0O41 0 00 0 0 1