当前位置: 首页 > news >正文

机器学习中数据集的划分难点及实现

数据划分中训练集、验证集、测试集的关系

一、数据划分的“三层结构”:训练集、验证集、测试集

为避免“模型过拟合测试数据”(即调参时依赖测试集性能,导致最终泛化能力评估不准),标准流程会将 原始数据集 DD 划分为三部分:

数据集作用是否参与“调参/模型选择”?
训练集用于训练模型参数(如神经网络权重、决策树分裂规则)是(模型学习的基础数据)
验证集用于评估不同参数模型的性能,辅助调参(选择最优参数)是(调参的“裁判”)
测试集仅在模型确定后使用,评估最终模型的泛化能力(模拟未来真实数据表现)(需严格“保密”)

二、流程拆解:为什么需要“先分训练/验证集调参,再用全量数据重训”?

第一步:原始数据 DD 划分为“训练集 TT”和“测试集 SS”(互不重叠)
  • 目的:确保测试集 SS 完全独立于模型训练过程,避免“用测试集信息调参”导致的评估偏差。
  • 例如:将 DD 按 7:3 划分为 TT(70% 数据,用于训练和调参)和 SS(30% 数据,仅用于最终评估)。
第二步:将“训练集 TT”再划分为“子训练集 TtrainTtrain​”和“验证集 TvalTval​”
  • 目的:在训练集 TT 内部完成“调参”,避免占用测试集 SS 的数据。
    • TtrainTtrain​:用于实际训练不同参数的模型(如用不同学习率训练 10 个模型)。
    • TvalTval​:作为“内部测试集”,评估这 10 个模型的性能,选出在 TvalTval​ 上表现最好的参数(即“调参”)。
  • 例如:将 TT 按 8:2 划分为 TtrainTtrain​(训练模型)和 TvalTval​(验证调参)。
第三步:用“全量训练集 TT”重新训练最终模型
  • 关键操作:当通过 TvalTval​ 选定最优参数后,需用 整个训练集 TT(包括 TtrainTtrain​ 和 TvalTval​)重新训练模型。
    • 为什么? 避免浪费数据:之前为了调参,TvalTval​ 未参与模型训练,现在参数确定后,用全部 TT 数据训练可让模型学习更充分。
第四步:用独立的“测试集 SS”评估最终模型
  • 此时的模型是用 全量训练集 TT 训练的,参数是通过 TvalTval​ 选定的,而测试集 SS 从未被模型“见过”,因此其评估结果能真实反映泛化能力。

三、疑问解答:“验证集从哪来?”“测试集和验证集是否冲突?”

  1. 验证集的来源: 验证集 来自训练集内部的划分(即从 TT 中拆分出 TvalTval​),而非原始数据 DD 单独划分。它是训练过程中的“临时裁判”,仅用于调参,调参结束后会“回归”训练集(即全量 TT 重训)。

  2. 测试集和验证集的关系:不冲突,各司其职

    • 验证集:属于“训练阶段”的工具,用于选择参数,数据来自训练集,会参与最终模型的重训(因此可能存在一定过拟合风险,但通过独立测试集可修正)。
    • 测试集:属于“评估阶段”的工具,数据完全独立于训练过程,不参与任何训练和调参,最终用于“检验”模型的真实泛化能力。
    • 比喻
      • 训练集 TT = 学生的“课本知识”,验证集 TvalTval​ = 老师的“随堂测验”(帮学生找到薄弱点,调整学习方法),测试集 SS = “高考”(完全独立,检验真实水平)。
      • 调参时用“随堂测验”(验证集)优化学习,最后用“课本全部内容”(全量训练集)复习,再参加“高考”(测试集)。

四、总结:完整流程示意图

核心结论

  • 验证集来自训练集内部,用于调参;测试集独立于训练过程,用于最终评估,二者不冲突。
  • “先用部分训练集调参,再用全量训练集重训” 是为了平衡“调参可靠性”和“数据利用率”——既通过验证集避免过拟合,又通过全量数据提升模型性能。

数据集划分函数调用---基于sklearn

    1.导入库

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris  # 采用鸢尾花数据集做测试 

'''
train_test_split()
参数:
- *arrays:这里用于接收一到多个列表、numpy数组、稀疏矩阵、padas 中的 DataFrame
- test_size: 测试集大小。可以是一个介于 0.0 和 1.0 之间的浮点数,表示测试集占总数据集的比例;也可以是一个整数,表示测试集的绝对大小
- train_size: 训练集大小。可以是一个介于 0.0 和 1.0 之间的浮点数,表示训练集占总数据集的比例;也可以是一个整数,表示训练集的绝对大小。如果未指定,则根据 test_size 自动计算
- random_state: 控制随机抽样的伪随机数生成器的种子。可以是一个整数,用于生成固定的随机数序列;可以是一个 RandomState 实例,用于自定义随机状态;也可以是 None,此时每次调用都会产生不同的随机状态
- shuffle:分类任务通常需要打乱数据(shuffle=True),但时间序列数据需设为 False 以避免未来信息泄露。
- stratify:当标签 y 的类别分布不均衡时(如 90% 正例,10% 负例),使用 stratify=y 可保证训练集和测试集的类别比例相同。
默认:
shuffle: Any = True,
stratify: Any = None

- 返回值:
- train_test_split 函数返回一个元组,包含分割后的数据集。具体返回值的数量取决于传入的数组数量。如果传入两个数组(如 X 和 y),则返回四个数组;如果传入三个数组,则返回六个数组,依此类推,对于两个数组的情况,返回值如下:
'''

def test2():dataset = load_iris()print(dataset)X = dataset.datay = dataset.targetX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)print("特征的训练数据集:", X_train)print("特征的测试数据集:", X_test)print("标签的训练数据集:", y_train)print("标签的测试数据集:", y_test)

        部分结果

通过初步学习,我们不免产生疑问如下:

疑问:打乱索引shuffle=True为什么最后标签和数据仍是一一对应的?
回答:

        indices = [0, 1, 2, 3]       # 原始索引shuffled_indices = [2, 0, 3, 1]  # 打乱后的索引# 按打乱后的索引重新排列数据X_shuffled = X[shuffled_indices]  # X[2], X[0], X[3], X[1]y_shuffled = y[shuffled_indices]  # y[2], y[0], y[3], y[1]#  详细往后看     

必要性:
训练需求:机器学习模型通常假设数据是独立同分布(i.i.d)的。如果数据本身有隐含顺序(如按类别或时间排序),直接拆分会导致训练集和测试集分布不一致。
例如:原始数据按类别排序(前50个是类别A,后50个是类别B),如果不打乱,训练集可能全是类别A,测试集全是类别B。
泛化性:随机化能让模型学习到更全面的数据分布,避免因数据顺序引入偏差。

这里我手动实现两种划分数据集的方法,不采用train_test_split api.

手把手实现train_test_split功能

        我们采用'titanic_train.csv'做测试,部分结构如下:

def homework_1():df = pd.read_csv('titanic_train.csv')# dataframe索引切片X_df = df.iloc[:, 0:-1]y_df = df.iloc[:, -1]# 转为数组便于操作使X,y维度一致X = X_df.valuesy = y_df.valuesprint(type(X), X.shape)print(type(y), y.shape)# 将标签转为二维数组y.shape = (len(y), 1)print(y.shape)# 不用随机数,选择训练集为0.8 测试集为0.2# 去掉最后一个样本,方便划分X = X[:-1, :]y = y[:-1, :]# 切片划分训练集和测试集X_train, X_test = X[0:int(0.8 * len(X)), :], X[int(0.8 * len(X)):, :]y_train, y_test = y[0:int(0.8 * len(y)), :], y[int(0.8 * len(y)):, :]print("特征的训练数据集:", X_train)print("特征的测试数据集:", X_test)print("标签的训练数据集:", y_train)print("标签的测试数据集:", y_test)'''
考虑到前面说到的随机化能让模型学习到更全面的数据分布,避免因数据顺序引入偏差。
手写数据集划分:使用随机数
'''def homework2():dataset = pd.read_csv('titanic_train.csv')# print(dataset.iloc[0:1])# print(type(dataset))print(len(dataset))# 去掉最后一个样本,方便划分dataset.drop(index=dataset.index[-1], axis='index', inplace=True)print(len(dataset))# 设置种子,确保每次划分一致random.seed(42)list = random.sample(range(len(dataset)), len(dataset))  # (可迭代对象,总数)# print(shuffled_df)# print(list)# print(len(list))# 替换每一行的顺序和list一致shuffled_df = dataset.iloc[list]# 切片划分数据集X_train, X_test = shuffled_df.iloc[0:int(0.8 * len(shuffled_df)), :-1], shuffled_df.iloc[int(0.8 * len(shuffled_df)):, :-1]y_train, y_test = shuffled_df.iloc[0:int(0.8 * len(shuffled_df)), -1:], shuffled_df.iloc[int(0.8 * len(shuffled_df)):, -1:]print(X_train.shape, y_train.shape)print(X_test.shape, y_test.shape)print(X_train)print(X_test)print(y_train)print(y_test)# print(i)

http://www.lryc.cn/news/617741.html

相关文章:

  • 计算机网络:1、OSI参考模型和TCP/IP模型
  • scikit-learn/sklearn学习|岭回归解读
  • 高并发场景下分布式ID生成方案对比与实践指南
  • Mini-Omni: Language Models Can Hear, Talk While Thinking in Streaming
  • Mining of Real-world Hypergraphs part1-2 逐字翻译解读
  • react中父子数据流动和事件互相调用(和vue做比较)
  • 剑桥大学最新研究:基于大语言模型(LLM)的分子动力学模拟框架,是MD的GPT时刻还是概念包装?
  • 机器翻译:Bahdanau注意力和Luong注意力详解
  • HarmonyOS AI辅助编程工具(CodeGenie)概述
  • 鸿蒙flutter项目接入极光推送
  • golang包管理工具中 GOPATH 与 Go Modules 的区别总结
  • 新人如何简化学习Vue3文件
  • while循环结合列表或字典
  • YOLOv6深度解析:实时目标检测的新突破
  • 企业架构工具篇之ArchiMate的HelloWorld(2)
  • Eino中的两种应用模式:“单独使用”和“在编排中使用”
  • 软考架构师:数据库的范式
  • 分治-归并-912.排序数组-力扣(LeetCode)
  • Catalyst 日志记录(Logging)
  • 石材 × 设计:解锁永恒材质的四大灵感密码
  • 获取MaixPy系列开发板机器码——MaixHub 模型下载机器码获取方法
  • ESP32 配合上位机串口打印数据
  • 【Web 服务的铁三角架构】Flask、Nginx 与 Docker 的分工与协作
  • FFmpeg - 基本 API大全(视频编解码相关的)
  • macOS 搭建 Gitea 私有 Git 服务器教程
  • wed前端第三次作业
  • 算法训练营DAY57 第十一章:图论part07
  • 缓存的三大问题分析与解决
  • STM32蓝牙模块驱动开发
  • 第10节 大模型分布式推理典型场景实战与架构设计