Python中如何利用分层抽样保证训练集与测试集的分布一致?

P粉602998670

P粉602998670

2026-08-04

573人浏览

原创

必须用train_test_split的stratify参数,因其能严格保证训练集和测试集中各类别占比与原始数据一致,避免小类样本在某子集中完全缺失;手动按比例切分无法规避随机性或小样本导致的分布偏斜,且stratify底层基于标签分组重采样,非简单切片。

python中如何利用分层抽样保证训练集与测试集的分布一致?

分层抽样为什么必须用 train_test_splitstratify 参数?

不用 stratify,哪怕你手动按类别比例切分,也可能因随机打乱顺序或样本量小导致某类在某个子集中完全缺失或严重偏斜。比如二分类中正样本只占 5%,若不用分层,测试集可能一个正样本都没有——模型压根没法评估召回率。train_test_split 内置的 stratify 会确保每个类在训练/测试集中占比严格一致(按四舍五入规则处理小数部分),且底层基于标签的分组重采样,不是简单按比例切片。

实操建议:

  • 必须传入与 X 行数对齐的 y(一维数组或 Series),不能是 DataFrame 或多列标签
  • y 中不能有空值(NaN),否则会报 ValueError: Input contains NaN
  • y 是字符串标签,需确保类别名无歧义(比如 "1"1 被视为不同类)

多分类 + 不均衡数据下 stratify 的实际表现

当类别数量多、某些类样本极少(比如 3 个样本的类),train_test_split 仍会尝试保留比例,但受限于最小整数约束:若测试集要分 20%,而某类只有 3 个样本,则测试集最多分 1 个(round(3 * 0.2) == 1),训练集剩 2 个。这会导致该类在训练集中样本过少,影响模型学习。

这时不能只依赖 stratify,得配合其他手段:

  • 检查各分类频次:np.bincount(y)y.value_counts(),提前发现极端稀疏类
  • 对极少数类可考虑过采样(如 imblearn.over_sampling.RandomOverSampler),但必须在分层之后、拟合前做,否则破坏分布一致性
  • 设置 test_size 时避开导致某类样本数 test_size=0.5 会分出 1.5 → 四舍五入为 2,但实际只分 1 或 2,取决于实现细节)

时间序列数据能用 stratify 吗?

不能。分层抽样假设样本独立同分布,而时间序列存在强自相关性。强行用 stratify 会把不同时段的同类样本混在一起,破坏时间先后逻辑,导致未来信息泄露。比如股票涨跌标签按日期排列,用 stratify 可能把 2023 年和 2024 年的“上涨”样本随机打散到训练/测试集,模型就偷看了未来走势。

Python 3.14.2
Python 3.14.2

Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。

下载

替代方案只有按时间切分:

  • TimeSeriesSplit 做滚动验证
  • 手动按日期阈值划分:train_mask = df['date'] ,再分别取 <code>X[train_mask]X[~train_mask]
  • 若必须保分布,只能先按时间窗口提取统计特征(如 7 日均值、波动率),再对这些静态特征做分层——但此时分层对象已是衍生特征,不是原始时序标签

自定义分层逻辑(比如按连续变量分箱后分层)

stratify 只接受离散标签,但你可以把连续变量 y_cont 转成离散分箱标签再传入。例如想按目标值大小分三层:

import numpy as np
from sklearn.model_selection import train_test_split
<h1>将连续目标转为三分位数分箱标签</h1><p>y_binned = np.digitize(y_cont, np.percentile(y_cont, [33, 66]))  # 得到 0/1/2 标签
X_train, X_test, y_train, y_test = train_test_split(
X, y_cont, test_size=0.2, stratify=y_binned, random_state=42
)</p>

注意点:

  • np.digitize 返回的是 bin 索引(从 0 开始),比 pd.cut(..., labels=False) 更可控
  • 分箱边界必须用训练集计算,测试集不能参与分箱——所以 np.percentile 必须只在训练集上运行,上面示例是简化写法,实际应先 fit 再 transform
  • 若分箱后某箱样本极少,同样会触发前述小样本问题,需检查 np.bincount(y_binned)

分层本身不难,难的是确认“分布一致”到底指什么——是类别比例?是目标值区间占比?还是业务定义的分群?选错分层依据,比不做分层更危险。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1104

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

2048

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1184

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

8639

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

1454

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

1526

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

860

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

530

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1087

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PyCharm官方快速入门指南
PyCharm官方快速入门指南

共0课时 | 0人学习

Python函数定义官方教程
Python函数定义官方教程

共0课时 | 0人学习

Python 3.14.6官方文档
Python 3.14.6官方文档

共0课时 | 0人学习