0%

机器学习之数据预处理:Encoding Categorical Variables 类别变量编码

数据预处理作为机器学习中的关键一环,这里介绍其中的Encoding Categorical Variables 类别变量编码

abstract.png

楔子

类别变量用于表示某种类别、属性,其值是一个名称或标签。对于类别变量而言,大体可分为两类:标称型、序数型

  • 标称型:类别之间没有内在的顺序或等级关系,无法比较大小或排序。类别之间是平等的,仅仅表示不同的标签。例如:血型、性别、颜色、城市。对于颜色(红色、蓝色、黄色)而言,总不能说红色比黄色大吧?
  • 序数型:类别之间存在清晰的、有意义的内在顺序或等级关系。类别之间可以进行比较、排序。例如:衣服尺码(S、M、L)。显然,L号的衣服比S号的衣服大,M号的衣服比L号的衣服小

但是对于类别变量而言,模型通常无法直接处理(字符串无法直接进行数学运算)。为此就需要将类别变量转化为数值变量

Label Encoding 标签编码

其编码方式很简单:将一维数据中的每个类别分别映射为一个整数。其适用特性:

  • 目标变量:其非常适合分类任务中样本集的目标变量。因为,对于目标变量而言,数值仅仅是作为一个标识符,不用于任何地比较、排序用途。例如,识别照片中动物的样本集,其目标变量为动物类别——狗(映射为0)、猫(映射为1)、虎(映射为2)、鸟(映射为3)、鱼(映射为4)

  • 序数型特征:对于序数型的类别特征,也可以使用其进行编码。因为可通过数值大小体现出类别间的排序规则。例如,衣服尺码(S、M、L)可以分别为映射为0、1、2

  • 标称型特征:对于标称型的类别特征,则绝对不可以使用该方式进行编码。这样会人为的给该类别引入一个虚假的的大小、排序关系。例如,对颜色特征进行编码(红 -> 0, 绿 -> 1, 蓝 -> 2),则模型可能会错误的认为蓝色比红色大。显然这并不合理

可以通过Sklearn中的LabelEncoder来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder

# 示例数据 (目标变量)
people_name = ['亚洲人', '非洲人', '亚洲人', '非洲人', '欧洲人']

# 创建 LabelEncoder 实例
le = LabelEncoder()
# 学习类别名称
le.fit(people_name)

print("映射关系: 类别名称 <<----->> 类别编号 ")
for i in range(le.classes_.size):
print(f"{le.classes_[i]} <<----->> {i}")

# 把类别名称转换为类别编号
people_index = le.transform(people_name)

print(f"基于类别名称的数据: {people_name}")
print(f"基于类别编号的数据: {people_index}")

# 把 类别编号 还原回 类别名称
people_name2 = le.inverse_transform(people_index)
print("基于类别编号的数据 还原为 基于类别名称 :", people_name2)

输出结果如下

1
2
3
4
5
6
7
映射关系: 类别名称 <<----->> 类别编号 
亚洲人 <<----->> 0
欧洲人 <<----->> 1
非洲人 <<----->> 2
基于类别名称的数据: ['亚洲人', '非洲人', '亚洲人', '非洲人', '欧洲人']
基于类别编号的数据: [0 2 0 2 1]
基于类别编号的数据 还原为 基于类别名称 : ['亚洲人' '非洲人' '亚洲人' '非洲人' '欧洲人']

One-Hot Encoding 独热编码

对于一个包含n种不同类别的一维数据,其使用一个n维的新数据来编码。其中,新数据中每个维度分别代表一种类别。这样当一个原始数据属于某个类别时,则其在新数据中的编码结果为:该类别对应维度的值为1,其余维度均为0。由于编码结果中只有一个1、其余皆为0,故得名 One-Hot

例如,对于颜色(红色、绿色、黑色)类别而言,这里有3种.我们可以规定:第1维表示绿色、第2维表示红色、第3维表示黑色。则:红色对应的编码即为 [0,1,0],绿色对应的编码即为 [1,0,0],黑色对应的编码即为 [0,0,1]

前面提到对于标称型的类别特征来说,如果使用Label Encoding标签编码会人为引入大小关系。因为彼此间的数值是可以比较大小的。而使用One-Hot Encoding独热编码就可以很好的解决这个问题。但该编码
会将该特征由原来的1个维度变为n个维度,显著增大数据维度,甚至出现维度灾难。同时,由于编码方式的特性,其编码结果中存在大量的0,会存在数据稀疏的问题

可以通过Sklearn中的OneHotEncoder来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from sklearn.preprocessing import OneHotEncoder
import numpy as np

# 原始特征: 颜色、价格
data = np.array([
['Red', 2.3],
['Green', 6.2],
['Blue', 7.34],
['Red', 13.83],
['Green', 5.5],
['Red', 7.2]
])

color_feature = data[:,0]
print(f"color_feature #1: {color_feature}")
print("-" * 100)

# 由于, OneHotEncoder要求输入是一个二维数组(行为样本、列为特征)
# 故, 对于一维数据调整形状为 (n_samples, 1)
color_feature = color_feature.reshape(-1,1)
print(f"color_feature #2:\n {color_feature}")
print("-" * 100)

# 创建 OneHotEncoder 实例
# handle_unknown属性:设为ignore。编码时如果遇到了未学习的类别,则其编码为全0,而不是抛出错误
oneHotEncoder = OneHotEncoder(handle_unknown='ignore', sparse_output=False)

# 学习类别
oneHotEncoder.fit(color_feature)

# 独热编码的位置顺序、每位编码对应的类别
color_categories = oneHotEncoder.categories_
print(f"特征Color 独热编码的位置顺序及对应的类别: {color_categories[0]}")
print("-" * 100)

# 把类别名称转换为独热编码
encoded_color = oneHotEncoder.transform(color_feature)

# 把 独热编码 还原回 类别名称
new_color_feature = oneHotEncoder.inverse_transform(encoded_color)

# 为独热编码后的特征的每一列创建一个列名
feature_names = oneHotEncoder.get_feature_names_out(['颜色'])

for i in range(feature_names.size):
print(f"{feature_names[i]} \t", end="" )
print("原始类别 \t 独热编码还原为类别")

m,_ = encoded_color.shape
for i in range(m):
print(f"{encoded_color[i,0]} \t\t {encoded_color[i,1]} \t\t {encoded_color[i,2]} \t\t {data[i,0]} \t\t {new_color_feature[i]}" )

输出结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
color_feature #1: ['Red' 'Green' 'Blue' 'Red' 'Green' 'Red']
----------------------------------------------------------------------------------------------------
color_feature #2:
[['Red']
['Green']
['Blue']
['Red']
['Green']
['Red']]
----------------------------------------------------------------------------------------------------
特征Color 独热编码的位置顺序及对应的类别: ['Blue' 'Green' 'Red']
----------------------------------------------------------------------------------------------------
颜色_Blue 颜色_Green 颜色_Red 原始类别 独热编码还原为类别
0.0 0.0 1.0 Red ['Red']
0.0 1.0 0.0 Green ['Green']
1.0 0.0 0.0 Blue ['Blue']
0.0 0.0 1.0 Red ['Red']
0.0 1.0 0.0 Green ['Green']
0.0 0.0 1.0 Red ['Red']

参考文献

  • 机器学习 周志华著
  • 机器学习公式详解 谢文睿、秦州著
  • 图解机器学习和深度学习入门 山口达辉、松田洋之著
请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝