类别特征编码:One-Hot、Label Encoding、Target Encoding
一句话概述
类别特征(Categorical Features)是机器学习中最常见的特征类型之一——性别、城市、商品类别等都属于类别特征。将类别特征转换为模型可处理的数值形式,称为「编码」(Encoding)。三大主流编码方法各有利弊:One-Hot Encoding 最简单但会导致高维稀疏,Label Encoding 紧凑但引入了虚假的序关系,Target Encoding 信息量大但有数据泄露风险。CatBoost 的 Ordered Target Encoding 解决了这一问题。
💡 核心要点:① One-Hot 编码适用于无序低基数类别特征,但不适合高基数特征(如用户 ID)② Label Encoding 简单但引入了虚假的序关系,适合树模型 ③ Target Encoding 利用目标变量信息,效果最好但需要防止数据泄露 ④ 高基数类别特征需要特殊处理:特征哈希、Embedding、频数编码
教学与演示
一、One-Hot Encoding
是什么:One-Hot Encoding(独热编码)为每个类别值创建一个新的二值(0/1)特征。对于有 k 个类别的特征,One-Hot 编码生成 k 个新特征,每个样本在对应其类别的特征上取值为 1,其余为 0。为避免多重共线性,线性模型通常使用 k−1 个特征(去除一个类别作为基准)。
大白话 One-Hot 编码就像「签到表」——每个类别一列,属于哪个类别就在哪一列打勾。简单明了,但类别多了表格就变得非常宽。
为什么:One-Hot 编码将每个类别映射到欧氏空间中的正交基向量,不同类别之间的距离相等(都是 √2),因此不会引入虚假的序关系或距离关系。对于逻辑回归、SVM、神经网络等需要计算距离或内积的模型,One-Hot 是最安全的编码方式。但高基数特征(如城市名有 1000 个不同值)会导致维度爆炸。
怎么做:
import numpy as np
# ========== One-Hot 编码实现演示 ==========
np.random.seed(42)
def one_hot_encoding_demo():
"""从零实现 One-Hot 编码"""
# 模拟类别特征数据
categories = np.array(['猫', '狗', '猫', '鸟', '狗', '猫', '鱼', '鸟'])
print("=== One-Hot 编码 ===")
print(f"原始类别: {categories}")
print()
# 获取所有唯一类别并排序
unique_cats = np.unique(categories)
print(f"唯一类别: {unique_cats}")
print(f"类别数: {len(unique_cats)}")
print()
# 手动实现 One-Hot 编码
n_samples = len(categories)
n_cats = len(unique_cats)
one_hot = np.zeros((n_samples, n_cats))
# 创建类别到索引的映射字典
cat_to_idx = {cat: i for i, cat in enumerate(unique_cats)}
for i, cat in enumerate(categories):
one_hot[i, cat_to_idx[cat]] = 1
print("One-Hot 编码结果(每个样本一行,每个类别一列):")
print(f" 列: {list(unique_cats)}")
for i in range(n_samples):
print(f" 样本{i}: {categories[i]:<4} → {one_hot[i].astype(int)}")
print(f"\n编码后形状: {one_hot.shape}")
print(f"特征数从 1 增加到 {n_cats}")
# ===== 降维:去除第一列(避免多重共线性) =====
print(f"\n为避免多重共线性,线性模型通常使用 k-1 = {n_cats-1} 列:")
one_hot_reduced = one_hot[:, 1:] # 去除第一列
print(f" '鸟' 作为基准类别(被去除)")
print(f" 编码后形状: {one_hot_reduced.shape}")
print(f" 树模型不需要这样做(不依赖线性关系)")
one_hot_encoding_demo()
# ===== One-Hot 编码的维度爆炸问题 =====
print("\n=== One-Hot 编码的维度爆炸 ===")
print("假设数据中有以下高基数特征:")
print(" 用户ID: 100万 → 100万列")
print(" 商品ID: 50万 → 50万列")
print(" 城市名: 1000 → 1000列")
print(" 总列数: 约150万 (维度爆炸!)")
print()
print("解决方案:")
print(" 1. 合并低频类别为「其他」")
print(" 2. 使用特征哈希(Feature Hashing)")
print(" 3. 使用 Embedding(如神经网络嵌入层)")
print(" 4. 使用 Target Encoding 代替 One-Hot")
大白话 One-Hot 编码是最安全的编码方式——它不会「误导」模型(不会告诉模型「猫 > 狗 > 鸟」),但代价是维度爆炸。如果类别数超过几百,就要考虑其他编码方式了。
二、Label Encoding 与 Ordinal Encoding
是什么:Label Encoding 将每个类别分配一个整数标签(如 0, 1, 2, ...)。Ordinal Encoding 是 Label Encoding 的特例,适用于有序类别特征(如「低」「中」「高」),且整数标签反映类别之间的序关系。Label Encoding 主要用于树模型,因为树模型的分裂不依赖于特征的数值大小。
大白话 Label Encoding 就是给每个类别贴个编号。问题是「猫=0, 狗=1, 鸟=2」会让线性模型以为「鸟 > 狗 > 猫」,这显然不对。但树模型不在乎——它只关心「是不是猫」,不关心编号大小。
为什么:树模型(决策树、随机森林、GBDT)处理 Label Encoding 是安全的——树的分裂是「x_j ≤ threshold」,对于标签编码的特征,分裂等价于「要不要把某些类别归为一组」。但线性模型(逻辑回归、SVM)会错误地将标签值解释为数值大小,引入虚假的序关系。因此:树模型 → Label Encoding 安全,线性模型 → 必须用 One-Hot。
怎么做:
import numpy as np
# ========== Label Encoding 与 Ordinal Encoding 演示 ==========
def label_encoding_demo():
"""演示 Label Encoding 和 Ordinal Encoding"""
print("=== Label Encoding ===")
# 无序类别特征
colors = np.array(['红', '蓝', '绿', '红', '蓝', '绿', '红'])
unique_colors = np.unique(colors)
color_to_label = {c: i for i, c in enumerate(unique_colors)}
label_encoded = np.array([color_to_label[c] for c in colors])
print(f"原始类别: {colors}")
print(f"Label 编码: {label_encoded} (映射: {color_to_label})")
print("注意:红=0, 蓝=1, 绿=2 → 线性模型会误以为 绿 > 蓝 > 红")
print(" 但树模型只关心「x==0?」→ 不会误解")
print()
# 有序类别特征
print("=== Ordinal Encoding(有序编码) ===")
sizes = np.array(['小', '中', '大', '大', '小', '中', '大'])
# 有序映射:保持原始顺序
size_order = {'小': 0, '中': 1, '大': 2}
ordinal_encoded = np.array([size_order[s] for s in sizes])
print(f"原始类别: {sizes}")
print(f"有序编码: {ordinal_encoded} (映射: {size_order})")
print("注意:这里 大>中>小 是有意义的关系 → 有序编码是正确的")
print()
# 对比:如果对有序特征用 One-Hot 会浪费信息
print("对比:有序特征用 One-Hot 编码会丢失序关系信息")
print(" 小 → [1, 0, 0]")
print(" 中 → [0, 1, 0]")
print(" 大 → [0, 0, 1]")
print(" One-Hot 中,小和中、中和大之间的距离相同 → 丢失了序信息")
label_encoding_demo()
# ===== 树模型 vs 线性模型 =====
print("\n=== 树模型 vs 线性模型对编码的敏感性 ===")
print("树模型: 分裂规则是 'x_j ≤ 2.5'")
print(" → 即使用 Label Encoding,树也能找到正确的分组")
print(" → 推荐用 Label Encoding(节省空间,速度快)")
print()
print("线性模型: 计算 w·x,x 的数值大小直接影响输出")
print(" → Label Encoding 引入虚假的数值关系")
print(" → 必须用 One-Hot Encoding")
大白话 记住一条规则:树模型用 Label Encoding,线性模型用 One-Hot。树模型不在乎你的编号是 0,1,2 还是 0,5,100——它只关心「是不是等于某个值」。线性模型就不一样了,它会认真对待每个数字的大小。
三、Target Encoding
是什么:Target Encoding(目标编码)用目标变量的统计量(如均值)来编码类别特征。对于每个类别值,计算该类别对应的目标变量均值(回归)或正类比例(分类),用这个值替换原始类别。为减少过拟合,通常加入平滑项或使用交叉验证。CatBoost 的 Ordered Target Encoding 是这方面的最佳实践。
大白话 Target Encoding 就是「用结果来给原因打分」——比如「北京」这个城市的用户平均购买率是 8%,那就用 0.08 来代表「北京」。这样编码出来的值直接携带了预测信息,比 One-Hot 的 0/1 要「聪明」得多。
为什么:Target Encoding 的最大优势是信息密度高——每个类别只用一个数值表示,不会维度爆炸,且这个数值直接反映了该类别与目标变量的关系。对于高基数特征(如用户 ID、商品 ID),这是唯一既高效又有效的编码方式。但风险是数据泄露——如果编码时使用了当前样本的目标值,会导致严重的过拟合。
怎么做:
import numpy as np
# ========== Target Encoding 演示 ==========
np.random.seed(42)
def target_encoding_demo():
"""演示 Target Encoding 及其数据泄露风险"""
n_samples = 200
# 模拟数据:不同城市有不同的购买率
cities = np.random.choice(['北京', '上海', '广州', '深圳', '杭州'], n_samples)
# 不同城市的真实购买率(模拟)
city_ctr = {
'北京': 0.08, '上海': 0.12, '广州': 0.06,
'深圳': 0.10, '杭州': 0.07
}
# 生成标签:各城市按对应概率产生购买行为
y = np.array([1 if np.random.random() < city_ctr[c] else 0 for c in cities])
print("=== Target Encoding ===")
print("数据: 城市 + 是否购买")
print()
# 方法1:普通 Target Encoding(有数据泄露风险)
print("--- 方法1:普通 Target Encoding(有泄露风险)---")
target_encoding = np.zeros(n_samples)
for city in np.unique(cities):
mask = cities == city
# 用所有样本(包括当前样本)计算均值 → 泄露!
target_encoding[mask] = y[mask].mean()
print("城市编码值(购买率):")
for city in np.unique(cities):
mask = cities == city
print(f" {city}: {target_encoding[mask][0]:.3f} (样本数: {mask.sum()})")
print("问题:当前样本的目标值参与了编码 → 过拟合!")
# 方法2:加平滑的 Target Encoding
print("\n--- 方法2:加平滑的 Target Encoding(减少过拟合)---")
global_mean = y.mean() # 全局均值作为先验
smoothing = 20 # 平滑参数(越大,越依赖全局均值)
smooth_encoding = np.zeros(n_samples)
for city in np.unique(cities):
mask = cities == city
n_city = mask.sum() # 该城市的样本数
city_mean = y[mask].mean() # 该城市的购买率
# 加权平均:样本数少时偏向全局均值
smooth_val = (n_city * city_mean + smoothing * global_mean) / (n_city + smoothing)
smooth_encoding[mask] = smooth_val
print("平滑编码值(smoothing=20):")
for city in np.unique(cities):
mask = cities == city
print(f" {city}: {smooth_encoding[mask][0]:.3f} (原始: {y[mask].mean():.3f})")
print("平滑使样本数少的城市的编码值向全局均值偏移 → 减少过拟合")
# 方法3:交叉验证 Target Encoding(CatBoost 的做法)
print("\n--- 方法3:K折交叉验证 Target Encoding(无泄露)---")
K = 5
fold_size = n_samples // K
cv_encoding = np.zeros(n_samples)
for fold in range(K):
val_start = fold * fold_size
val_end = (fold + 1) * fold_size
val_idx = list(range(val_start, val_end))
train_idx = [i for i in range(n_samples) if i not in val_idx]
# 只用训练集计算编码
for city in np.unique(cities):
city_mask = cities == city
city_train = city_mask & np.isin(np.arange(n_samples), train_idx)
city_val = city_mask & np.isin(np.arange(n_samples), val_idx)
if city_train.sum() > 0:
cv_encoding[city_val] = y[city_train].mean()
else:
cv_encoding[city_val] = global_mean
print(f"K={K} 折交叉验证编码(无信息泄露)")
print(f"编码值范围: [{cv_encoding.min():.3f}, {cv_encoding.max():.3f}]")
target_encoding_demo()
大白话 Target Encoding 的平衡艺术:样本多的类别,相信数据本身;样本少的类别,相信全局平均值。这个平衡由平滑参数 m 控制。CatBoost 更进一步——用交叉验证确保每个样本的编码值不包含自身的目标信息,彻底杜绝数据泄露。
什么用:Target Encoding 在 Kaggle 竞赛中是处理高基数类别特征的「标配」技巧。在 CTR 预估中,用户 ID 和商品 ID 的目标编码比 One-Hot 编码效果好得多。在信用评分中,城市、职业等类别特征的目标编码能直接反映「该特征值对应的违约率」。
哪些坑:数据泄露是 Target Encoding 的最大风险——必须在交叉验证框架下计算编码,绝对不能使用测试集的目标信息。稀有类别(样本数极少)的编码值不可靠,需要平滑。Target Encoding 对目标变量的分布假设敏感,如果目标变量是二分类,建议使用对数几率(log-odds)而非原始比例。
四、其他编码方法
是什么:除了三大主流方法,还有许多针对特定场景的编码方法:频数编码(Count/Frequency Encoding)——用类别出现频数替换,特征哈希(Feature Hashing)——用哈希函数将类别映射到固定维度,嵌入编码(Embedding Encoding)——通过神经网络学习低维嵌入向量,以及 WOE 编码(Weight of Evidence)——常用于信用评分领域。
大白话 编码方法就像工具箱里的各种工具——锤子(One-Hot)适合钉钉子,螺丝刀(Target Encoding)适合拧螺丝。没有万能工具,只有最合适的工具。
为什么:频数编码简单但信息量有限(只反映类别频率,不反映与目标的关系)。特征哈希解决了高基数问题但可能产生哈希冲突(不同类别映射到同一位置)。嵌入编码是深度学习的标准做法——将每个类别映射到一个低维稠密向量,通过反向传播学习最优表示。WOE 编码在信用评分卡中广泛使用,衡量每个类别对「好/坏」样本的区分能力。
怎么做:
import numpy as np
# ========== 其他编码方法演示 ==========
np.random.seed(42)
def other_encoding_demo():
"""演示频数编码、特征哈希和 WOE 编码"""
# 模拟数据
cities = np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '南京'], 200)
y = np.random.binomial(1, 0.3, 200) # 二分类标签
print("=== 其他编码方法 ===")
# 1. 频数编码(Count Encoding)
print("--- 频数编码 ---")
from collections import Counter
city_counts = Counter(cities)
n = len(cities)
count_encoding = np.array([city_counts[c] / n for c in cities]) # 频率
print(" '北京' 出现次数:", city_counts['北京'], f"→ 频率: {city_counts['北京']/n:.3f}")
print(" 优点: 简单,不维度爆炸")
print(" 缺点: 不同类别可能有相同频率,信息量有限")
# 2. 特征哈希(Feature Hashing)
print("\n--- 特征哈希 ---")
n_features = 5 # 哈希到的维度
hash_encoding = np.zeros((len(cities), n_features))
for i, city in enumerate(cities):
# 用哈希函数映射到 0 ~ n_features-1
hash_val = hash(city) % n_features
hash_encoding[i, hash_val] = 1
print(f" 原始类别数: {len(np.unique(cities))}")
print(f" 哈希后维度: {n_features}")
print(f" 压缩比: {len(np.unique(cities)) / n_features:.1f}x")
print(" 优点: 固定维度,不受类别数影响")
print(" 缺点: 可能哈希冲突(不同类别映射到同一位置)")
# 3. WOE 编码(Weight of Evidence)
print("\n--- WOE 编码(信用评分常用) ---")
# 假设 y=1 是「坏客户」,y=0 是「好客户」
total_good = np.sum(y == 0) # 好客户总数
total_bad = np.sum(y == 1) # 坏客户总数
woe_encoding = np.zeros(len(cities))
for city in np.unique(cities):
mask = cities == city
good = np.sum((y == 0) & mask) # 该城市的好客户数
bad = np.sum((y == 1) & mask) # 该城市的坏客户数
# WOE = ln(好客户比例 / 坏客户比例)
# 加小值防止除零
woe = np.log((good + 0.5) / total_good * total_bad / (bad + 0.5))
woe_encoding[mask] = woe
print(" WOE = ln(好客户分布 / 坏客户分布)")
for city in np.unique(cities)[:3]:
mask = cities == city
print(f" {city}: WOE = {woe_encoding[mask][0]:.3f}")
print(" WOE > 0 → 该类别偏向好客户;WOE < 0 → 偏向坏客户")
print(" 优点: 直接反映类别对目标的区分能力")
print(" 缺点: 需要标签,有数据泄露风险")
other_encoding_demo()
# ===== 编码方法选择指南 =====
print("\n=== 编码方法选择指南 ===")
guide = [
("低基数(<10)", "无序", "线性模型", "One-Hot"),
("低基数(<10)", "无序", "树模型", "Label / One-Hot"),
("低基数(<10)", "有序", "任意模型", "Ordinal"),
("高基数(>100)", "无序", "线性模型", "Target / Feature Hashing"),
("高基数(>100)", "无序", "树模型", "Label / Target"),
("超高基数(>1000)", "无序", "任意模型", "Embedding / Feature Hashing"),
]
for card, order, model, method in guide:
print(f" 基数{card:<10} {order:<4} {model:<10} → {method}")
大白话 编码方法的选择取决于三个因素:① 类别数量(低基数 vs 高基数),② 类别是否有序,③ 用什么模型(树模型 vs 线性模型 vs 神经网络)。记住这个决策树,编码就不会做错。
概念关系图谱
| 编码方法 | 输出维度 | 保持序关系 | 适用模型 | 主要风险 |
|---|---|---|---|---|
| One-Hot | k 或 k-1 | 否 | 线性/神经网络 | 维度爆炸 |
| Label | 1 | 假序 | 树模型 | 虚假序关系 |
| Ordinal | 1 | 真序 | 所有 | 需正确指定序 |
| Target | 1 | 可能 | 所有 | 数据泄露 |
| Count/Freq | 1 | 可能 | 树模型 | 信息量有限 |
| Feature Hashing | 固定 d | 否 | 所有 | 哈希冲突 |
| Embedding | 固定 d | 否 | 神经网络 | 需大量数据 |
重点答疑
Q1: 为什么树模型可以用 Label Encoding 而线性模型不行?
树模型的分裂规则是「x_j ≤ threshold」,对于 Label Encoding 后的整数特征,分裂等价于将某些类别归为一组。树模型不关心数值的大小关系,只关心「等于」或「不等于」。线性模型则计算 w·x,x 的数值大小直接影响输出——Label Encoding 中「猫=0, 狗=1, 鸟=2」会让模型误以为「鸟的效应是狗的 2 倍」,这完全没有意义。
Q2: Target Encoding 如何防止数据泄露?
核心原则是:在计算每个样本的编码值时,绝对不能使用该样本自身的目标值。实现方法:① K 折交叉验证——每个样本的编码值只用不包含该样本的折来计算,② 平滑——稀有类别的编码值向全局均值收缩,③ 添加噪声——在编码值上添加微小随机噪声。CatBoost 的 Ordered Target Encoding 通过随机排序和只用历史样本的机制,优雅地解决了这个问题。
Q3: 高基数类别特征(如用户 ID)应该怎么处理?
三种主流方案:① Target Encoding——用 K 折交叉验证计算每个用户的平均目标值,② Embedding——通过神经网络将每个用户 ID 映射到一个低维稠密向量(如 64 维),类似于 Word2Vec 的思想,③ Feature Hashing——用哈希函数将用户 ID 映射到固定维度(如 1000 维),容忍少量哈希冲突。方案①最简单高效,方案②在深度学习场景中效果最好,方案③是极端基数下的兜底方案。
章节单词汇总
| 英文 | 音标 | 术语/释义 |
|---|---|---|
| One-Hot Encoding | /wʌn hɑːt ɪnˈkoʊdɪŋ/ | 独热编码;每个类别一列,0/1 表示 |
| Label Encoding | /ˈleɪbəl ɪnˈkoʊdɪŋ/ | 标签编码;用整数代替类别 |
| Ordinal Encoding | /ˈɔːrdɪnəl ɪnˈkoʊdɪŋ/ | 有序编码;整数反映类别顺序 |
| Target Encoding | /ˈtɑːrɡɪt ɪnˈkoʊdɪŋ/ | 目标编码;用目标变量均值编码 |
| Feature Hashing | /ˈfiːtʃər ˈhæʃɪŋ/ | 特征哈希;用哈希函数压缩维度 |
| Embedding | /ɪmˈbedɪŋ/ | 嵌入;用低维稠密向量表示类别 |
| WOE | /ˌdʌbəl.juː.oʊˈiː/ | Weight of Evidence;证据权重 |
| Data Leakage | /ˈdeɪtə ˈliːkɪdʒ/ | 数据泄露;编码时使用了未来信息 |
面试练习
Q1 [单选] 对于线性回归模型,颜色特征「红、蓝、绿」应该使用哪种编码?
- A. One-Hot Encoding
- B. Label Encoding
- C. Ordinal Encoding
- D. 不需要编码
解答:颜色是无序类别特征,线性模型对数值大小敏感,应该使用 One-Hot Encoding。Label Encoding 会引入「绿 > 蓝 > 红」的虚假序关系。
Q2 [单选] 对于随机森林模型,城市特征「北京、上海、广州」的最佳编码方式是什么?
- A. One-Hot Encoding(必须)
- B. Label Encoding
- C. Target Encoding
- D. 不需要编码
解答:树模型对数值大小不敏感,Label Encoding 是安全且高效的。One-Hot 也可以但会增加维度,Target Encoding 也可以但需要防泄露。
Q3 [多选] Target Encoding 的主要风险是什么?
- A. 数据泄露(编码时使用了当前样本的目标值)
- B. 稀有类别的编码值不可靠
- C. 维度爆炸
- D. 无法处理有序特征
解答:Target Encoding 的主要风险是数据泄露(需要交叉验证避免)和稀有类别编码不可靠(需要平滑处理)。它不会维度爆炸(每个类别只占一个数值),也能处理有序特征。
Q4 [单选] 平滑 Target Encoding 中,平滑参数 m 的作用是什么?
- A. 控制编码的维度
- B. 平衡「类别均值」和「全局均值」的权重
- C. 控制编码的计算速度
- D. 决定使用 One-Hot 还是 Label Encoding
解答:平滑参数 m 控制编码值在类别均值和全局均值之间的偏向。当类别样本数 n_c 远小于 m 时,编码值偏向全局均值(保守);当 n_c 远大于 m 时,编码值偏向类别均值(信任数据)。
Q5 [单选] 特征哈希(Feature Hashing)的主要缺点是什么?
- A. 计算太慢
- B. 哈希冲突——不同类别可能映射到同一位置
- C. 只能用于二分类
- D. 无法处理数值特征
解答:特征哈希用哈希函数将类别映射到固定维度,不同类别可能映射到同一位置(哈希冲突),导致信息丢失。维度越大,冲突概率越低,但压缩效果越差。
Q6 [多选] 以下哪些编码方法不会导致维度爆炸?
- A. Label Encoding
- B. Target Encoding
- C. Count/Frequency Encoding
- D. One-Hot Encoding
解答:Label、Target、Count Encoding 都是每个特征只输出一个数值,维度不随类别数增长。One-Hot Encoding 输出维度等于类别数,高基数特征会导致维度爆炸。
Q7 [单选] WOE 编码(Weight of Evidence)最常用于什么领域?
- A. 图像分类
- B. 信用评分卡(Credit Scoring)
- C. 自然语言处理
- D. 时间序列预测
解答:WOE 编码是信用评分卡开发中的标准做法,它衡量每个特征取值对「好客户 vs 坏客户」的区分能力,是逻辑回归评分卡模型的核心预处理步骤。
Q8 [单选] 对于有序类别特征「低、中、高」,正确的编码方式是?
- A. One-Hot Encoding
- B. Label Encoding(随机映射)
- C. Ordinal Encoding(按序映射:低=0, 中=1, 高=2)
- D. Target Encoding
解答:有序类别特征应使用 Ordinal Encoding,保持类别之间的序关系。One-Hot 会丢失序信息,Label Encoding 的映射可能不正确(如果随机映射)。
Q9 [多选] 以下哪些是 CatBoost 在处理类别特征时的特色?
- A. Ordered Target Encoding(避免数据泄露)
- B. 自动生成类别特征组合
- C. 不需要手动预处理类别特征
- D. 使用 One-Hot Encoding 作为默认编码
解答:CatBoost 的三大特色是:Ordered Target Encoding(防泄露)、自动特征组合、原生支持类别特征输入(无需手动编码)。它默认使用自己的 Target Encoding 变体,而非 One-Hot。
Q10 [单选] 在训练集和测试集上做 Target Encoding 时,正确的做法是?
- A. 训练集和测试集分别独立计算编码
- B. 在训练集上计算编码值,然后应用到测试集上
- C. 在训练集+测试集上一起计算编码
- D. 只在测试集上计算编码
解答:正确的做法是:在训练集上(通过交叉验证)计算编码值,然后将这些编码值应用到测试集上。不能在测试集上计算编码(信息泄露),也不能在训练集+测试集上一起计算(同样泄露)。