4、特征编码技术:Label Encoding、One-Hot Encoding、Target Encoding、自动化编码策略选择

特征编码,说白了就是把非数值型数据变成模型能吃的数字。这件事看起来简单,但坑特别多。我见过不少项目,模型效果上不去,最后发现是编码方式选错了。

今天咱们就把几种主流编码方式掰开揉碎讲清楚。我会结合自己的实战经验,告诉你什么时候该用哪种,以及怎么让整个过程自动化。

4.1 Label Encoding:最简单的映射

Label Encoding 就是把每个类别映射成一个整数。比如「红、黄、蓝」变成 0、1、2。

听起来很直接对吧?但这里有个大坑——模型会认为这些数字有大小关系。0 < 1 < 2,模型会以为「蓝」比「红」大。这在有序类别(比如「小、中、大」)上没问题,但在无序类别上就出事了。

我曾经在一个电商项目中,把「省份」做了 Label Encoding。结果模型学出来「北京=0,上海=1,广东=2」,它居然认为广东比北京「大」。这完全没道理。后来我换成 One-Hot,效果立刻好了。

什么时候用 Label Encoding?

  • 类别本身有顺序(比如学历:小学 < 中学 < 大学)
  • 类别数量特别多(几百个),One-Hot 会撑爆内存
  • 树模型(决策树、随机森林)对顺序不敏感,可以凑合用
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
data['education_encoded'] = le.fit_transform(data['education'])
# 小学→0, 中学→1, 大学→2

4.2 One-Hot Encoding:最稳妥的选择

One-Hot 把每个类别变成一列 0/1 向量。比如颜色有红、黄、蓝三种,就生成三列:is_red、is_yellow、is_blue。

这样做的好处是——模型不会误解类别之间的关系。每个类别都是独立的,没有大小之分。

但代价也很明显:维度爆炸。如果某个特征有 1000 个类别,就会多出 1000 列。我做过一个用户画像项目,光「城市」这个特征就产生了 300 多列,训练集直接翻了三倍。

我个人习惯:类别数 < 10 时,无脑用 One-Hot。10~50 之间,看模型。50 以上,考虑其他方案。
import pandas as pd

# 直接用 pandas 的 get_dummies
one_hot = pd.get_dummies(data['color'], prefix='color')
data = pd.concat([data, one_hot], axis=1)

4.3 Target Encoding:用标签信息编码

Target Encoding 是个「作弊」技巧——用目标变量的均值来编码类别。比如计算每个城市的平均房价,然后用这个均值代替城市名。

这样做的好处是:一个特征就能表达类别信息,不会维度爆炸。而且编码后的特征和目标变量直接相关,模型学起来很快。

但风险也很大——过拟合。如果某个类别只有几条样本,它的均值可能完全不准。我见过一个项目,某个「职业」类别只有 2 个人,Target Encoding 后模型直接记住了这两个人的标签,泛化能力一塌糊涂。

避坑指南:一定要做交叉验证或平滑处理。常用的做法是加入全局均值做加权平均:
encoded = (n * group_mean + m * global_mean) / (n + m)
其中 n 是类别样本数,m 是平滑参数。
def target_encoding_smooth(df, feature, target, m=10):
    global_mean = df[target].mean()
    group_stats = df.groupby(feature)[target].agg(['mean', 'count'])
    group_stats['encoded'] = (
        group_stats['count'] * group_stats['mean'] + 
        m * global_mean
    ) / (group_stats['count'] + m)
    return df[feature].map(group_stats['encoded'])

4.4 四种编码方式对比

编码方式 适用场景 优点 缺点
Label Encoding 有序类别、类别极多 简单、不增加维度 引入虚假顺序关系
One-Hot Encoding 无序类别、类别少 无顺序假设、模型友好 维度爆炸、稀疏
Target Encoding 高基数类别、有标签信息 维度低、信息密度高 容易过拟合
Frequency Encoding 类别分布差异大 简单、保留频次信息 丢失类别语义

4.5 自动化编码策略选择

手动选编码方式太累了。你想想看,一个数据集可能有几十个类别特征,每个都要人工判断?不现实。

我设计了一套自动化规则,直接写进 pipeline 里:

  1. 判断类别是否有顺序:如果有,用 Label Encoding
  2. 判断类别数量:< 10 用 One-Hot,10~50 看模型类型
  3. 判断模型类型:线性模型用 One-Hot,树模型用 Label
  4. 高基数(> 50):用 Target Encoding + 交叉验证
  5. 兜底方案:Frequency Encoding
我建议:把这套规则封装成一个函数,输入特征名和元数据,自动返回编码方式。这样每次跑新数据,一行代码就能搞定。
def auto_encoder_selector(feature, n_categories, is_ordinal, model_type):
    if is_ordinal:
        return 'label_encoding'
    if n_categories < 10:
        return 'one_hot'
    if 10 <= n_categories <= 50:
        if model_type == 'linear':
            return 'one_hot'
        else:
            return 'label_encoding'
    if n_categories > 50:
        return 'target_encoding'
    return 'frequency_encoding'

4.6 知识体系总览

下面这张图把编码技术的选择逻辑串起来了。你可以把它当作决策地图,遇到新数据时照着走一遍。

特征编码自动化决策流程 类别特征 是否有顺序? 是 Label Encoding 否 判断类别数量 数量 < 10 One-Hot Encoding 10 ≤ 数量 ≤ 50 看模型类型 数量 > 50 Target Encoding 线性模型 One-Hot Encoding 树模型 Label Encoding 💡 核心原则 类别少→One-Hot 类别多→Target Encoding

4.7 实战中的坑与建议

最后分享几个我踩过的坑:

  • 测试集和训练集要分开编码:尤其是 Target Encoding,必须用训练集计算均值,再映射到测试集。否则就是数据泄露。
  • 新类别处理:线上预测时可能出现训练集没见过的类别。我习惯在编码时加一个「unknown」兜底。
  • 不要迷信一种编码:同一个数据集,不同特征可以用不同编码。我做过一个项目,城市用 Target Encoding,性别用 One-Hot,学历用 Label,效果比统一编码好很多。
总结一句话:编码没有银弹。理解每种方法的原理和局限,结合自动化规则,才能在实际项目中又快又好地搞定特征编码。