target encoding 在高基数分类变量上比 one-hot 更实用,但需正确使用平滑和交叉验证;one-hot 在类别数超100时导致内存暴涨、训练变慢且模型效果下降;target encoding 必须避免标签泄露,采用 k 折 cv 和平滑项,否则线上效果崩塌。

Target Encoding 在高基数分类变量上确实比 One-Hot 更实用,但前提是做对了平滑和交叉验证——否则效果反而更差。
类别数超过100时One-Hot会直接拖垮内存和训练速度
One-Hot 把一个含 N 个类别的特征转成 N 列稀疏矩阵。当 N = 2000(比如城市名、SKU ID),100万行数据用 float64 存储就至少吃掉 16GB 内存;XGBoost 或 LightGBM 训练时间可能从几分钟涨到几小时,且分裂节点效率大幅下降。
- 实测:某电商用户城市字段(1852个唯一值)+ 80万样本 →
pd.get_dummies()后 DataFrame 内存增长 3.7 倍 - 树模型不擅长从大量零值列中识别信号,容易把低频类别当成噪声忽略
-
pd.get_dummies(..., sparse=True)可缓解但不解决根本问题,且部分模型(如 sklearn 的 LogisticRegression)不兼容稀疏输入
Target Encoding 本质是用统计信息压缩维度,但必须防标签泄露
它把每个类别映射为该类样本的 target 均值(比如“北京”用户平均复购率=0.42),输出仍是单列浮点数,维度不变、信息密度高。但直接用全局均值会把测试集信息“泄露”进训练过程,导致 CV 分数虚高、线上效果崩塌。
- 错误做法:
df.groupby('city')['target'].transform('mean')—— 这是典型的数据泄漏 - 正确做法必须满足两个条件:① 用 K 折交叉验证生成编码(如
category_encoders.TargetEncoder(cv=5));② 加平滑项(smooth=10或更高),尤其对低频类别(出现次数 - LightGBM/XGBoost 对浮点型编码友好,无需额外归一化;但线性模型需注意缩放,否则梯度更新失衡
LabelEncoder 和 TargetEncoder 不是替代关系,而是场景分工
LabelEncoder 给类别分配 0~N−1 整数,适合有序变量(如 ['低','中','高'])或树模型处理高基数无序特征——但它隐含等距假设,会误导模型认为“上海”比“北京”大1、“广州”比“上海”大1。
- TargetEncoder 没这个假设,靠目标分布说话;但依赖
y,不能用于纯无监督场景 - 若类别与
target几乎无关(卡方检验 p > 0.05),TargetEncoder 反而引入噪声,此时频率编码(CountEncoder)或留空更稳妥 - 业务强解释需求下(如风控规则需人工核验),TargetEncoder 数值不易解读,不如分箱+One-Hot 控制粒度
真正容易被忽略的不是“用不用 TargetEncoder”,而是平滑系数 smooth 和交叉验证折数 cv 的组合是否匹配你的数据分布——小样本(cv=3 + smooth=5,大样本(>50万)可尝试 cv=10 + smooth=20,不调这两项,和没用一样。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











