Press "Enter" to skip to content

机器学习基石:深入理解独热编码(One-Hot Encoding)

在处理机器学习问题时,我们接触到的数据多种多样,不仅有数值型的连续数据,还有类别丰富的离散数据,比如性别、年级、城市等。然而,大多数机器学习模型都偏爱“吃”数值型数据,对于文本类别的特征常常感到“消化不良”。为了让模型能理解这些类别信息,我们需要对它们进行预处理,而独热编码(One-Hot Encoding)就是其中最常用、最重要的一种技术。

为什么需要独热编码?

想象一下,我们有这样一个关于学生信息的特征:

  • 年级: ["初一", "初二", "初三"]

最直观的想法是,直接将它们映射成数字,例如:初一 -> 0, 初二 -> 1, 初三 -> 2。 这样做虽然简单,但却引入了一个它本不存在的问题:顺序性

对于机器学习模型来说,数字的大小和顺序是有意义的。它会认为“初三”(2)是“初二”(1)的两倍,或者“初三” > “初二” > “初一”。但实际上,“年级”这个特征的三个类别之间是平等的,并不存在这种数学上的大小或顺序关系。 这种错误的假设会误导模型,影响其学习效果。

为了解决这个问题,独热编码应运而生。它的核心思想是用一个向量来表示一个类别,做到所有类别在数值表示上是相互独立的、平等的

什么是独热编码?

独热编码,又称“一位有效编码”,具体做法是:

  1. 统计一个特征下共有多少个不同的类别(N个)。
  2. 创建一个长度为N的向量(可以理解为N个新的特征列)。
  3. 对于每一个样本,它在原始特征中的值对应哪个类别,就在新向量的哪个位置上标记为1,其余位置全部标记为0。

简单来说,就是有多少个类别,就分裂成多少个新的特征,每个特征只用0或1来表示“是”或“否”。

举个例子,还是上面的“年级”特征:

  • 初一 变为 [1, 0, 0]
  • 初二 变为 [0, 1, 0]
  • 初三 变为 [0, 0, 1]

这样一来,每个类别都被表示成一个独立的、没有大小关系的向量,模型就不会再被错误的顺序信息所干扰。

再看一个多特征的例子:
假设一个学生小明的特征是 "男生", "初一", "来自二中"。

  • 性别: ["男", "女"]
  • 年级: ["初一", "初二", "初三"]
  • 学校: ["一中", "二中", "三中", "四中"]

经过独热编码后,小明的特征向量会是:

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

这个向量由三部分拼接而成:

  • [1, 0] 代表 "男"
  • [1, 0, 0] 代表 "初一"
  • [0, 1, 0, 0] 代表 "二中"

如何用Python实现独热编码?

在Python中,我们可以非常方便地使用 pandasscikit-learn 库来实现独热编码。

1. 使用 pandas.get_dummies()

pandas 是数据分析的利器,它的 get_dummies() 函数可以一键完成独热编码,非常直观。

import pandas as pd

# 创建一个DataFrame
data = {'年级': ['初一', '初二', '初三', '初一']}
df = pd.DataFrame(data)

# 使用get_dummies进行独热编码
one_hot_df = pd.get_dummies(df['年级'], prefix='年级')

print(one_hot_df)

输出结果:

   年级_初一  年级_初二  年级_初三
0      1      0      0
1      0      1      0
2      0      0      1
3      1      0      0

2. 使用 sklearn.preprocessing.OneHotEncoder

scikit-learn 是专业的机器学习库,它提供的 OneHotEncoder 更加强大和灵活,尤其适合在机器学习的Pipeline(管道)中使用。

from sklearn.preprocessing import OneHotEncoder
import numpy as np

# 创建一个二维数组,因为OneHotEncoder需要二维输入
data = np.array([['初一'], ['初二'], ['初三'], ['初一']])

# 初始化编码器
# sparse_output=False 表示输出密集矩阵(数组),而不是稀疏矩阵
encoder = OneHotEncoder(sparse_output=False)

# 拟合数据并转换
one_hot_encoded = encoder.fit_transform(data)

print(one_hot_encoded)

输出结果:

[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]]

scikit-learnfit_transform 方法会先学习(fit)数据中有哪些类别,然后再进行转换(transform)。当有新的数据需要转换时,可以直接调用 transform 方法,确保新旧数据使用相同的编码规则。

独热编码的优缺点

优点

  1. 解决类别特征数值化问题:将离散特征转换为模型易于处理的数值格式。
  2. 消除顺序性:处理了类别间不存在大小顺序的问题,避免对模型产生误导。
  3. 提升模型性能:在一定程度上扩大了特征空间,可能有助于提升模型的非线性能力。

缺点

  1. 维度灾难:当一个特征的类别数量非常多时(例如,城市、ID),独热编码会产生大量的新特征,导致数据矩阵变得非常稀疏(大部分值为0),这会大大增加计算复杂度和存储开销。
  2. 信息丢失:它假设所有类别之间是完全独立的,但有时类别之间可能存在某些关联,独热编码无法表达这种关联。

总结

独热编码是特征工程中一个基础且强大的工具,它为机器学习模型处理类别型数据架起了一座重要的桥梁。虽然它存在维度爆炸等问题,但在类别数量可控的情况下,它通常是处理离散特征的首选方法。理解其背后的原理和实现方式,是每一位数据科学家和机器学习工程师的必备技能。

参考资料:https://cloud.tencent.com/developer/article/1688022

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注