返回首页

Roadmap
更新于 2026年10月21日 全文 2168 字未阅读

类别型数据:词表与独热编码#

维度(dimension),其实就是特征向量(feature vector)里元素个数的另一个说法。

有些类别型特征的维度很低,低到你可以一眼看完它的全部取值:

特征名类别数类别样例
snowed_today2True、False
skill_level3初学者、熟练者、专家
season4冬、春、夏、秋
day_of_week7星期一、星期二、星期三……
planet8水星、金星、地球……

词表#

类别数量不多时,我们就可以把它编码成一份词表(vocabulary)。用词表编码之后,模型会把每一个可能的类别取值,当成一个独立特征来对待;在训练过程中,模型会为每个类别分别学到一组权重。

举个例子。假设你要训练一个模型,根据车漆颜色 car_color 来预测汽车的价格——说不定红色的车就是比绿色的贵。由于各家厂商能提供的车漆颜色是有限的,car_color 就属于一个低维度的类别型特征。

下面这张图给出了 car_color 的一份词表(也就是所有可能的取值):

图 1. 一组车漆颜色的调色板:调色板里的每一种颜色各自对应特征向量中的一个独立特征位——红色是一个特征,橙色是另一个特征,以此类推。
图 1. 每个类别对应一个独一无二的特征

索引编号#

模型只会处理浮点数。所以我们必须把每个字符串转换成一个独一无二的索引编号,就像下面这张图:

图 2. 与图 1 相同的调色板,但现在每个颜色旁边标着一个整数索引:红色对应 0,橙色对应 1,以此类推。
图 2. 索引化后的特征

不过,把字符串换成索引编号只是第一步。要真正让模型学到取值之间有意义的关系,还得再往下走一层。因为——如果类别型特征就这么以索引整数的形态被送进模型,模型会把这些编号当成连续的浮点数来看待。换个说法,它会认为 "Purple" 的可能性是 "Orange" 的六倍。

独热编码#

搭好词表之后的下一步,是把每个索引编号转换成它的独热编码(One-hot encoding。

在独热编码里:

  • 每个类别都由一个长度为 N 的向量(数组)表示,N 就是类别的数量。比如 car_color 一共有 8 个可能的类别,那么代表它的独热向量就有 8 个元素。

  • 一个独热向量里,有且仅有一个元素的值是 1,其余元素的值全是 0。

下面这张表就是 car_color 中每种颜色对应的独热编码:

特征RedOrangeBlueYellowGreenBlackPurpleBrown
“Red”10000000
“Orange”01000000
“Blue”00100000
“Yellow”00010000
“Green”00001000
“Black”00000100
“Purple”00000010
“Brown”00000001

注意,真正被放进特征向量的是独热向量,而不是字符串本身、也不是索引编号。模型会为特征向量里的每一个元素分别学到一组权重。

提示: 真正的独热编码中,只有一个元素的值是 1.0。在一种被称为多热编码(multi-hot encoding)的变体里,可以有多个元素的值同时是 1.0。

MLWM:关于多热编码,一个典型场景就是垃圾邮件分类场景,我们就需要用一个多热编码向量来表示一封邮件,然后使用模型来对这封邮件进行分类,可以参见「词袋模型原理:文本特征表示与机器学习建模」 中的介绍。

下面这张图展示了词表表示中各种转换的全过程:

图 3. 从类别到特征向量的端到端流程图:输入依次是 Yellow、Orange、Blue、Blue。系统先用存好的词表(Red 是 0、Orange 是 1、Blue 是 2、Yellow 是 3,以此类推)把输入值映射成编号 3、1、2、2,再把这些编号各自展开成独热向量,例如 3 变成 0, 0, 0, 1, 0, 0, 0, 0。
图 3. 从类别到特征向量的端到端转换过程

稀疏表示#

取值绝大部分是零(或者空)的特征,我们称之为稀疏特征(Sparse feature)。很多类别型特征,比如 car_color,天然就是稀疏特征。

稀疏表示(Sparse representation),指的是只存储那个 1.0 所在的位置。例如,"Blue" 对应的独热向量是:

[0, 0, 1, 0, 0, 0, 0, 0]

因为这个 1 位于第 2 位(从 0 开始数),所以上面这个独热向量的稀疏表示就是:

2

不难看出,稀疏表示占用的内存远小于 8 个元素的独热向量。但要特别强调的是:模型必须用独热向量来训练,而不是稀疏表示。

提示: 多热编码的稀疏表示,存储的是所有非零元素的位置。例如,一辆同时是 "Blue" 和 "Black" 的车,它的稀疏表示是 2, 5。

类别型数据中的离群值#

和数值型数据一样,类别型数据里也有离群值。假设 car_color 里除了那些常见颜色之外,还混进了一些极少用到的离群颜色,比如 "Mauve"(藕荷色)或 "Avocado"(牛油果绿)。

我们当然可以给每一种离群颜色都单开一个类别,但更好的做法是:把它们统统塞进一个叫作词表外(out-of-vocabulary, OOV)的「万能」类别里。换句话说,所有离群颜色都被分箱进同一个离群桶里,模型则为这个桶单独学一组权重。

高维类别型特征的编码#

词嵌入#

有些类别型特征的维度非常高,比如下面这张表里的几个:

特征名类别数类别样例
words_in_english~500,000“happy”、“walking”
US_postal_codes~42,000“02114”、“90301”
last_names_in_Germany~850,000“Schmidt”、“Schneider”

当类别数量很多时,独热编码通常是个糟糕的选择。更好的选择是嵌入(Embeddings)——我们在单独的嵌入模块中详细讲过。嵌入能大幅压缩维度,这给模型带来两方面的好处:

  • 模型训练通常会更快。

  • 构建好的模型做预测推断通常也更快,也就是延迟更低。

哈希#

哈希(Hashing),也叫哈希小技巧(hashing trick),则是另一种不那么常用的降维方式。简单说,哈希是把一个类别(比如某种颜色)映射到一个小整数——也就是那个「用来装这个类别的桶」的编号。

具体来说,哈希算法是这样实现的:

  1. 把类别向量里的桶数设为 N,其中 N 要小于剩余类别的总数。举一个随意的例子,假设 N = 100。

  2. 选定一个哈希函数。(通常你也会一并选定哈希值的取值范围。)

  3. 把每个类别(比如某一种具体颜色)送进这个哈希函数,得到一个哈希值,比如 89237。

  4. 把输出哈希值对 N 取模,得到每个桶的索引编号。此处 N = 100、哈希值为 89237,取模结果是 37,因为 89237 % 100 = 37。

  5. 用这些新的索引编号,为每个桶生成一份独热编码。

关于哈希数据的更多细节,可以参考生产机器学习系统模块中随机化(Randomization)一节的内容。


小测验:检验你的理解#

判断并说明:一个机器学习模型可以直接在 "Red"、"Black" 这样的原始字符串取值上训练,而不必先把这些取值转换成数值向量。

  • 正确(True)

  • 错误(False)

点击查看答案

错误(False)

训练过程中,模型只能操作浮点数。字符串 "Red" 不是浮点数,所以你必须先把 "Red" 这样的字符串转换成浮点数。

关键术语:

  • 类别型数据(Categorical data)
  • 维度(Dimensions)
  • 离散特征(Discrete feature)
  • 特征交叉(Feature cross)
  • 特征向量(Feature vector)
  • 哈希(Hashing)
  • 独热编码(One-hot encoding)
  • 稀疏特征(Sparse feature)
  • 稀疏表示(Sparse representation)
阅读 --