3. 特征编码技术:Label Encoding、One-Hot Encoding、Target Encoding 的原理与实战对比

特征编码,说白了就是把非数值型数据变成模型能吃的数字。我见过太多新手直接把「男」「女」扔进模型,结果跑出来的结果一塌糊涂。你想想看,模型底层全是矩阵运算,它哪认识什么「北京」「上海」?

这一章,咱们就把三种最常用的编码技术掰开揉碎讲清楚。我会结合自己踩过的坑,告诉你什么时候该用哪个。

3.1 为什么需要特征编码?

大部分机器学习算法只吃数值。决策树稍微好点,但像线性回归、SVM、神经网络这些,你给个字符串进去,它直接报错给你看。

我遇到过最离谱的一次,有个同事把「省份」列直接做 Label Encoding,结果模型学出了「北京 < 上海 < 广州」这种大小关系。嗯,地理老师看了想打人。

核心原则:编码方式决定了模型能学到什么样的信息。选错了,模型就学歪了。

3.2 Label Encoding(标签编码)

Label Encoding 最简单——给每个类别分配一个整数。比如「红=0, 绿=1, 蓝=2」。

什么时候用?

  • 类别之间有明显的顺序关系(比如「小=0, 中=1, 大=2」)
  • 树模型(决策树、随机森林、XGBoost)——它们不怕数值大小
  • 类别数量特别多(几百上千个),One-Hot 会炸内存

什么时候千万别用?

  • 类别之间没有顺序关系(颜色、国家、职业)
  • 线性模型、神经网络——它们会当真去算「2 比 1 大」

我曾经踩过的坑:有一次做房价预测,把「街道名称」做了 Label Encoding。结果模型学出来「A街道=1, B街道=2, C街道=3」,它以为 C 街道的房子就该比 A 街道贵两倍。实际上这三个街道的房价差不多。后来换成 One-Hot,效果立刻好了。

# Label Encoding 示例
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
data['color_encoded'] = le.fit_transform(data['color'])
# 输出:红→0, 绿→1, 蓝→2

3.3 One-Hot Encoding(独热编码)

One-Hot 把每个类别变成一个独立的 0/1 列。比如「红=100, 绿=010, 蓝=001」。

优点:不引入任何顺序关系,模型不会学出虚假的大小关系。

缺点:列数爆炸。如果有 1000 个城市,就多出 1000 列。

我个人的习惯:

  • 类别数 < 10 且没有顺序关系 → 直接用 One-Hot
  • 类别数 10~50 → 看情况,内存够就用
  • 类别数 > 50 → 考虑 Target Encoding 或者先做聚类再编码
# One-Hot Encoding 示例
import pandas as pd

data = pd.get_dummies(data, columns=['color'], prefix='color')
# 输出:color_red, color_green, color_blue 三列 0/1

小技巧:用 pd.get_dummies 时记得加 drop_first=True,扔掉第一列避免多重共线性。线性模型特别吃这一套。

3.4 Target Encoding(目标编码)

Target Encoding 用目标变量的均值来替换类别。比如「北京的房子均价 500 万,上海 600 万,那就用 500 和 600 来编码」。

这招在 Kaggle 竞赛里特别常见。我打比赛时,光靠 Target Encoding 就能把 CV 分数拉高 0.01~0.02。

优点:

  • 不增加维度(一列换一列)
  • 直接编码了类别与目标的关系
  • 对树模型和线性模型都有效

致命缺点:容易过拟合。尤其是某个类别样本很少的时候,均值可能完全不准。

避坑指南:做 Target Encoding 必须用 K-Fold 交叉验证的方式计算均值。不能拿全量数据算完再分训练集和测试集——那叫数据泄露,模型在测试集上会死得很难看。

# Target Encoding 示例(带 K-Fold 平滑)
from category_encoders import TargetEncoder

encoder = TargetEncoder(cols=['city'], smoothing=10)
data['city_encoded'] = encoder.fit_transform(data['city'], data['price'])

3.5 三种编码的对比

特性 Label Encoding One-Hot Encoding Target Encoding
维度变化 不变 暴增 不变
引入顺序关系 是 否 否
过拟合风险 低 低 高(需 K-Fold)
适用模型 树模型 所有模型 所有模型
类别数 > 100 推荐 不推荐 推荐
类别有顺序 推荐 可用 可用

3.6 实战选择策略

我一般按这个流程走:

  1. 先看类别有没有顺序——有顺序直接 Label Encoding
  2. 再看类别数量——少于 10 个且无顺序,One-Hot
  3. 10~50 个——试 One-Hot,内存炸了就换 Target Encoding
  4. 超过 50 个——Target Encoding 或者先做频次编码
  5. 如果是树模型——Label Encoding 往往就够用,省事
  6. 如果是线性模型或神经网络——优先 One-Hot 或 Target Encoding

我的经验:别死磕一种编码。我经常在同一个数据集里混用——有序的用 Label,无序且少的用 One-Hot,无序且多的用 Target Encoding。模型效果往往比只用一种好。

3.7 知识体系总览

下面这张图把三种编码的核心逻辑和适用场景串起来了。你可以把它当成决策地图。

特征编码技术决策地图 原始类别特征 有顺序关系? 是 Label Encoding 否 看类别数量 < 10 One-Hot Encoding > 50 Target Encoding 提示:树模型优先 Label Encoding;线性模型/神经网络优先 One-Hot 或 Target Encoding

3.8 一个真实案例

去年我做了一个电商用户画像项目。用户所在地有 300 多个城市,直接用 One-Hot 的话,特征矩阵会多出 300 列。训练集 50 万样本还好,但线上推理时内存直接爆了。

我当时的做法:

  • 先把城市按购买力分成 5 档(一线、二线、三线、四线、其他)——这是 Label Encoding
  • 再对原始城市做 Target Encoding,用 K-Fold 计算平均客单价
  • 两个特征一起喂给 LightGBM

结果 AUC 从 0.72 涨到了 0.78。说白了,组合编码往往比单一编码效果好。

我的建议:别把编码方式当成固定套路。多试几种组合,用验证集效果说话。特征工程没有银弹,只有不断试错。