stratifiedkfold是一种分层k折交叉验证器,通过按类别分组并在每组内均匀分配索引,确保每折训练集和验证集的类别比例与原始数据集一致,从而避免类别分布失衡导致的评估偏差。

什么是StratifiedKFold,它为什么能保持类别分布
StratifiedKFold 是 scikit-learn 提供的分层 K 折交叉验证器,核心目标是在每一折的训练集和验证集中,各类别样本比例尽可能与原始数据集一致。它不是简单地打乱后切分,而是先按类别分组、再在每组内均匀分配索引,最后拼接成各折——所以即使某类只有 5 个样本,它也不会全被分进同一折。
常见错误是误用 KFold 处理分类任务:比如二分类中正样本仅占 5%,用 KFold 可能导致某折验证集一个正样本都没有,评估结果严重失真。
- 只适用于目标变量为离散类别(
y是整数或字符串标签),不支持回归任务 - 要求每个类别的样本数 ≥ 折数(否则报
ValueError: The least populated class has only n members) - 默认不打乱顺序;如需随机性,必须显式设
shuffle=True并指定random_state
如何正确初始化并生成训练/验证索引
关键在于传入真实标签 y,且确保 y 的长度与特征矩阵 X 行数一致。生成的索引是纯数字位置,不依赖 DataFrame 索引或行名。
from sklearn.model_selection import StratifiedKFold
import numpy as np
<p>X = np.random.randn(1000, 10)
y = np.array([0] <em> 950 + [1] </em> 50) # 极度不平衡二分类</p><p>skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
print(f"训练集类别分布: {np.bincount(y[train_idx])}")
print(f"验证集类别分布: {np.bincount(y[val_idx])}")
break # 只看第一折示例
</p>
-
n_splits=5表示 5 折,每折验证集约占 20% 样本 -
shuffle=True和random_state=42保证可复现的随机划分 - 输出中两行
bincount应近似保持 95:5 比例(如训练集 760:40,验证集 190:10)
配合 cross_val_score 或手动训练时的注意事项
直接传给 cross_val_score 最省事,但要注意 estimator 必须支持 fit/score 接口;手动训练则需用索引切片 X 和 y,不能直接用 train_test_split 替代。
- 用
cross_val_score时,cv参数直接传StratifiedKFold实例,不要传n_splits整数 - 若
y是 pandas Series,确保其值类型是 category 或 int,避免因隐式转换导致分层失效 - 对时间序列或多标签分类任务,
StratifiedKFold不适用——它假设样本独立同分布 - 当类别极不均衡(如少数类仅 1–2 个样本),考虑改用
StratifiedShuffleSplit或自定义分组策略
验证是否真的保持了分布:一个快速检查方法
别只信文档,运行时打印各折的 np.unique(y[indices], return_counts=True) 是最直接的验证方式。尤其在预处理后(如采样、过滤)重新划分前,务必确认 y 未被意外修改。
- 如果某折中某个类别计数为 0,先检查
y是否含空值或非法类型(如NaN、None) - 使用
pandas.value_counts()查看原始y分布,和各折输出对比,差值超过 ±1 通常就说明分层异常 - 注意:分层是“近似保持”,不是绝对均等;小样本类别在折间可能浮动 1 个样本,这属于正常行为
真正容易被忽略的是:分层只作用于你传入的 y 这一维标签。如果你有多个目标(如多任务学习)、或标签本身是嵌套结构(如 list of lists),StratifiedKFold 会静默失败——它根本无法理解这种语义。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











