目录
一、什么是one-hot编码?
One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。
One-Hot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。
一句话概括:one hot编码是将类别变量转换为机器学习算法易于利用的一种形式的过程。
二、为什么要用onehot
假设我们有一个迷你数据集:
公司名 |
类别值 |
价格 |
小米 |
1 |
5000 |
华为 |
2 |
10011 |
中兴 |
3 |
50000 |
中兴 |
3 |
10000 |
在上面的表格中,类别值从1开始,更符合日常生活中的习惯。实际项目中,类别值从0开始(因为大多数计算机系统计数),所以,如果有N个类别,类别值为0至N-1.
sklear的LabelEncoder可以帮我们完成这一类别值分配工作。
根据标签编码的类别值,我们的迷你数据集中小米> 华为> 中兴。比方说,假设模型内部计算平均值(神经网络中有大量加权平均运算),那么1 + 3 = 4,4 / 2 = 2. 这意味着:VW和Honda平均一下是Acura。毫无疑问,这是一个糟糕的方案。该模型的预测会有大量误差。
我们使用one hot编码器对类别进行“二进制化”操作,然后将其作为模型训练的特征,原因正在于此。
当然,如果我们在设计网络的时候考虑到这点,对标签编码的类别值进行特别处理,那就没问题。不过,在大多数情况下,使用one hot编码是一个更简单直接的方案。如下表:
小米 |
华为 |
中兴 |
价格 |
1 |
0 |
0 |
5000 |
0 |
1 |
0 |
10011 |
0 |
0 |
1 |
50000 |
0 |
0 |
1 |
10000 |
注:如果原本的标签编码是有序的,那one hot编码就不合适了——会丢失顺序信息。
三、什么情况下使用onehot
对于定类类型的数据,建议使用one-hot encoding。定类类型就是纯分类,不排序,没有逻辑关系。比如性别分男和女,男女不存在任何逻辑关系,我们不能说男就比女好,或者相反。再者,中国各省市分类也可以用独热编码,同样各省不存在逻辑关系,这时候使用one-hot encoding会合适些。但注意,一般会舍去一个变量,比如男的对立面肯定是女,那么女就是重复信息,所以保留其中一个变量即可。
对于定序类型的数据,建议使用label encoding。定序类型也是分类,但有排序逻辑关系,等级上高于定类。比如,学历分小学,初中,高中,本科,研究生,各个类别之间存在一定的逻辑,显然研究生学历是最高的,小学最低。这时候使用Label encoding会显得更合适,因为自定义的数字顺序可以不破坏原有逻辑,并与这个逻辑相对应。
对数值大小敏感的模型必须使用one-hot encoding或者Dummy。典型的例子就是LR和SVM。二者的损失函数对数值大小是敏感的,并且变量间的数值大小是有比较意义的。而Label encoding的数字编码没有数值大小的含义,只是一种排序,因此对于这些模型都使用one-hot encoding。
对数值大小不敏感的模型(如树模型)不建议使用one-hot encoding。一般这类模型为树模型。如果分类类别特别多,那么one-hot encoding会分裂出很多特征变量。这时候,如果我们限制了树模型的深度而不能向下分裂的话,一些特征变量可能就因为模型无法继续分裂而被舍弃损失掉了。因此,此种情况下可以考虑使用Label encoding
四、使用举例:
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
data =[['法师', 40, 14000],
['辅助', 30, 13000],
['坦克', 31, 12000],
['射手', 30, 14000],
['法师', 32, 11000]]
data = pd.DataFrame(data, columns=['role', 'changci', 'output'])
# print (data)
# 在One-Hot编码之前先将带中文的标称属性转换成数值型
# 用简单整数替代
listUniq = data.loc[:, 'role'].unique() # 去重
# 对匹配的元素赋值,不匹配的元素保持原样
for j in range(len(listUniq)):
data.loc[:, 'role'] = data.loc[:, 'role'].apply(lambda x: j if x == listUniq[j] else x)
print(data)
# 用数字给文本属性赋值,保证赋值过的不会重新再赋值
# lambda x:j if x == listUniq[j] else x
# 遍历len(listUniq)次 data.loc[:,'role']
# 发现data.loc[:,'role'] 中有元素与listUniq的元素相同,就赋相对应的整数值
# 开始One-Hot编码
temp = data[['role']]
enc = OneHotEncoder()
enc.fit(temp)
# 将Matrix类型转换为array类型
temp = enc.transform(temp).toarray()
tempdata = pd.DataFrame(temp,columns=['role1','role2','role3','role4'])
tempdata['changci']=data[['changci']]
tempdata['output']=data[['output']]
print(tempdata)
运行结果: