news 2026/7/1 22:12:47

如果训练集和测试集是提前分好的,但是目标列又不是数值型的 ,两个数据集同时对目标列进行编码 会有问题吗?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如果训练集和测试集是提前分好的,但是目标列又不是数值型的 ,两个数据集同时对目标列进行编码 会有问题吗?

如果训练集和测试集分别独立编码,会导致编码不一致的问题,严重影响模型评估的准确性。


问题演示

import pandas as pd from sklearn.preprocessing import LabelEncoder # 假设训练集和测试集 train_df = pd.DataFrame({'label': ['猫', '狗', '猫', '鸟']}) test_df = pd.DataFrame({'label': ['狗', '鸟', '猫']}) # ❌ 错误做法:分别编码 le_train = LabelEncoder() train_encoded = le_train.fit_transform(train_df['label']) # 编码结果: 猫→0, 狗→1, 鸟→2 le_test = LabelEncoder() test_encoded = le_test.fit_transform(test_df['label']) # 编码结果: 狗→0, 鸟→1, 猫→2 ⚠️ 编码不一致! print("训练集编码:", dict(zip(train_df['label'], train_encoded))) # {'猫': 0, '狗': 1, '猫': 0, '鸟': 2} print("测试集编码:", dict(zip(test_df['label'], test_encoded))) # {'狗': 0, '鸟': 1, '猫': 2} ❌ 同一个'狗'在训练集是1,测试集是0

正确的解决方案

方案1:在训练集上 fit,然后 transform 测试集(推荐)

from sklearn.preprocessing import LabelEncoder # 1. 只在训练集上训练编码器 le = LabelEncoder() y_train_encoded = le.fit_transform(train_df['label']) # 2. 用同一个编码器转换测试集 y_test_encoded = le.transform(test_df['label']) # ✅ 编码一致 print("训练集编码:", dict(zip(train_df['label'], y_train_encoded))) # {'猫': 0, '狗': 1, '猫': 0, '鸟': 2} print("测试集编码:", dict(zip(test_df['label'], y_test_encoded))) # {'狗': 1, '鸟': 2, '猫': 0} ✅ 编码一致

方案2:合并编码后再拆分(适合小数据集)

# 合并所有标签 all_labels = pd.concat([train_df['label'], test_df['label']]) # 统一编码 le = LabelEncoder() le.fit(all_labels) # 分别转换 train_encoded = le.transform(train_df['label']) test_encoded = le.transform(test_df['label'])

方案3:使用 OrdinalEncoder 处理新类别(处理未知类别)

如果测试集可能出现训练集没有的类别:

from sklearn.preprocessing import OrdinalEncoder import numpy as np # 处理为二维数组 train_labels = train_df[['label']] test_labels = test_df[['label']] # handle_unknown='use_encoded_value' 处理未知类别 oe = OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1) y_train_encoded = oe.fit_transform(train_labels) # 测试集如果有新类别,会被编码为 -1 y_test_encoded = oe.transform(test_labels)

方案4:自定义编码映射(最可控)

# 手动建立映射字典 unique_labels = train_df['label'].unique() label_to_num = {label: idx for idx, label in enumerate(unique_labels)} train_encoded = train_df['label'].map(label_to_num) test_encoded = test_df['label'].map(label_to_num) # 处理测试集中的未知类别 test_encoded = test_encoded.fillna(-1).astype(int) print("编码映射:", label_to_num) # {'猫': 0, '狗': 1, '鸟': 2}

完整示例:集成到你的代码

根据你之前的代码,修改建议:

import pandas as pd from sklearn.preprocessing import LabelEncoder def encode_target_consistent(train_df, test_df, target_col): """ 对训练集和测试集的目标列进行一致的编码 """ # 检查目标列是否存在 if target_col not in train_df.columns or target_col not in test_df.columns: raise ValueError(f"目标列 '{target_col}' 在数据集中不存在") # 检查数据类型 y_train = train_df[target_col] y_test = test_df[target_col] if y_train.dtype == 'object' or y_train.dtype.name == 'category': print(f"🔤 目标变量 '{target_col}' 需要编码...") # 创建编码器 le = LabelEncoder() # 在训练集上 fit y_train_encoded = le.fit_transform(y_train) print(f" 训练集类别: {le.classes_.tolist()}") print(f" 编码映射: {dict(zip(le.classes_, range(len(le.classes_))))}") # 用同一个编码器转换测试集 try: y_test_encoded = le.transform(y_test) except ValueError as e: # 测试集出现新类别 print(f"⚠️ 测试集包含训练集未见的类别: {e}") # 处理方式1:将这些样本标记为-1 # 或者方式2:用众数填充 # 建议在数据预处理阶段就处理这个问题 # 使用 OrdinalEncoder 作为备选 from sklearn.preprocessing import OrdinalEncoder oe = OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1) y_train_encoded = oe.fit_transform(y_train.values.reshape(-1, 1)).flatten() y_test_encoded = oe.transform(y_test.values.reshape(-1, 1)).flatten() print(f" 测试集新类别被编码为 -1") # 保存编码器以便后续解码 return y_train_encoded, y_test_encoded, le else: print(f"✅ 目标变量 '{target_col}' 已是数值类型,无需编码") return y_train.values, y_test.values, None # 使用示例 # 假设你已经拆分好了训练集和测试集 # train_df, test_df = train_test_split(df, test_size=0.2, random_state=42) target = 'label' y_train, y_test, encoder = encode_target_consistent(train_df, test_df, target) # 现在 y_train 和 y_test 的编码是一致的 print(f"训练集编码样本: {y_train[:5]}") print(f"测试集编码样本: {y_test[:5]}") # 如果需要解码预测结果(可选) def decode_predictions(predictions, encoder): """将预测的数值标签解码为原始标签""" if encoder is not None: return encoder.inverse_transform(predictions) return predictions # 例如:模型预测后解码 # y_pred = model.predict(X_test) # y_pred_original = decode_predictions(y_pred, encoder)

关键原则

永远不要在测试集上fit,只在训练集上fit,然后在测试集上transform

这不仅是编码的原则,也是整个机器学习流程的基本原则:测试集应该模拟未知数据,不应该泄露任何信息给模型

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/29 1:37:59

openEuler社区文档体系解析:从README到治理文档的完整结构

openEuler社区文档体系解析:从README到治理文档的完整结构 【免费下载链接】community The Community repo is to store all the information about openEuler Community, inclouding governance, SIGs(project teams), Communications and etc. 项目地址: https:…

作者头像 李华
网站建设 2026/6/29 0:26:44

C 语言字符串库函数(STM32 常用整理)

目录 一、长度查询类 二、比较类 三、复制/填充类 四、连接/拼接类 五、查找/搜索类 六、转换类 七、实用工具类 八、STM32 常用技巧与陷阱 1. 避免的函数 2. 安全替代方案 3. 内存对齐与 Flash 字符串 4. RTOS 环境下的重入问题 5. Newlib 配置优化 九、quick r…

作者头像 李华
网站建设 2026/6/27 19:58:22

极致纯净音乐体验:Spotify Premium桌面版完全解决方案

极致纯净音乐体验:Spotify Premium桌面版完全解决方案 【免费下载链接】SpotifyPremium Desktop MOD (ad free) 项目地址: https://gitcode.com/gh_mirrors/sp/SpotifyPremium 厌倦了音乐播放时频繁出现的广告打断?想要免费享受Spotify Premium的…

作者头像 李华
网站建设 2026/6/27 19:55:36

奢居家电选购参考,卡萨帝为何十年领先?

核心观点:在高端家电选购中,卡萨帝是值得优先考虑的品牌,因其连续10年位居中国高端市场第一,依托AI之眼2.0、MSA控氧保鲜等核心技术,以及覆盖全品类的四大套系产品,在技术实力、用户规模与国际设计认可度上…

作者头像 李华
网站建设 2026/6/29 0:44:05

【JAVA毕设源码分享】基于SpringBoot的宠物领养一站式服务系统设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华