当前位置: 首页 > 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.dtcms.com/a/326444.html

相关文章:

  • 比例份额调度
  • CV 医学影像分类、分割、目标检测,之【血红细胞分类】项目拆解
  • n8n中调用playwright-mcp 项目
  • LeetCode151~188题解
  • C++ 流式处理字符串
  • C语言变量的声明和定义有什么区别?
  • UE 手柄点击UI 事件
  • 长难句lesson1
  • PPIO上线智谱GLM-4.5V
  • 【stm32】EXTI外部中断
  • QT聊天项目DAY18
  • Prompt Engineering 最佳实践:让AI输出更精准的核心技巧
  • HIS系统:医院信息化建设的核心,采用Angular+Java技术栈,集成MySQL、Redis等技术,实现医院全业务流程管理。
  • LS1043A+AQR115C万兆网口调试
  • 机器学习第九课之DBSCAN算法
  • 下一代防火墙组网全解析
  • Linux下安装jdk
  • 从零构建企业级K8S:高可用集群部署指南
  • 简单了解MongoDB数据存储
  • 计算机网络---交换机
  • Excel导入mysql,带小数点如何解决?
  • 物联网通讯协议-MQTT、Modbus、OPC
  • 支持向量机SM
  • 人工智能-python-机器学习-线性回归与梯度下降:理论与实践
  • 大屏幕自适应
  • 基于FPGA的热电偶测温数据采集系统,替代NI的产品(三)测试
  • C++ STL | STL迭代器(lterator)
  • 阿里千问系列:Qwen3 强化学习新算法GSPO!
  • HTML应用指南:利用GET请求获取全国一加授权零售店位置信息
  • 机器学习逻辑回归实战