数据集划分策略:训练集、验证集、测试集的划分原则,分层采样与交叉验证

做模型验证这么多年,我见过太多人在这上面栽跟头。说白了,数据集怎么切,直接决定了你评估出来的精度靠不靠谱。今天咱们就把这事聊透。

一、三大集合:各司其职

先搞清楚三个集合分别干嘛用的。我习惯这么理解:

  • 训练集:喂给模型学习的,相当于学生的课本和习题。
  • 验证集:调参时用的,相当于模拟考。你调学习率、改网络层数,都得看验证集的表现。
  • 测试集:最终大考。模型训练完、参数定好之后,只用这一次。测完就封存,不能再回头改模型。

核心原则:测试集绝对不能参与任何训练决策。 我在项目中遇到过有人不小心把测试集泄露到调参流程里,结果上线后精度直接崩了10个点。嗯,血的教训。

二、划分比例:经验值 vs 数据量

常见的比例是 6:2:2 或 7:1.5:1.5。但别死记硬背,得看数据量说话。

数据总量 建议训练集 建议验证集 建议测试集
1000 条 70% 15% 15%
10 万条 80% 10% 10%
100 万条+ 98% 1% 1%

你想想看,数据量大的时候,验证集和测试集各1万条就足够稳定评估了。没必要硬切20%。

三、分层采样:别让分布失衡

直接随机切分有个大坑——类别分布可能跑偏。比如二分类问题,原始数据正负样本比是 9:1。随机一切,验证集里可能变成 9.5:0.5,测试集里变成 8.5:1.5。这评估结果能准吗?

分层采样就是干这个的。它保证每个子集里各类别的比例和原始数据一致。

from sklearn.model_selection import train_test_split

# 普通随机切分
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 分层采样切分
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

看到没?就多了一个 stratify=y。我个人习惯,只要做分类任务,必加这个参数。哪怕数据看起来平衡,也加上。又不费事,图个安心。

小技巧: 回归任务也可以用分层采样。把目标变量分成几个区间,按区间分层。比如房价预测,按价格区间 0-50万、50-100万、100万+ 分层切分。

四、交叉验证:小数据的救星

数据量少的时候,怎么切都觉得不够用。这时候交叉验证就派上用场了。

最常用的是 K 折交叉验证。把数据分成 K 份,每次拿 K-1 份训练,1 份验证。轮 K 次,取平均。

from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print(f'5折交叉验证平均精度: {scores.mean():.3f}')

K 一般取 5 或 10。我曾经试过 K=3,方差太大,结果忽高忽低。K=10 比较稳,但计算量也上去了。小数据集用 5 折,够用。

五、分层交叉验证:双重保险

把分层采样和交叉验证结合起来,就是分层 K 折交叉验证。每一折里都保持类别比例。

from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
    X_train, X_val = X[train_idx], X[val_idx]
    y_train, y_val = y[train_idx], y[val_idx]
    # 训练和验证

为什么要 shuffle?防止数据本身有顺序。比如前 1000 条全是类别 A,后 1000 条全是类别 B。不 shuffle 的话,某一折可能全是 A,没法训练。

注意: 时间序列数据不能用普通交叉验证。会泄露未来信息。得用时间序列专用的 TimeSeriesSplit 或滚动窗口验证。我曾经在这上面吃过亏,模型在历史数据上表现完美,一上线预测未来就崩了。

六、知识体系总览

下面这张图把整个数据集划分策略串起来了。我建议你保存下来,做项目时对照着看。

数据集划分策略知识体系 原始数据集 训练集 (60-80%) 验证集 (10-20%) 测试集 (10-20%) 随机划分 分层采样 交叉验证 简单随机 分层随机 K折交叉验证 分层K折 时间序列交叉 数据量大时适用 保持类别比例 小数据量首选 双重保险 防止未来泄露 核心目标:评估结果真实可靠,泛化能力强

七、实战建议

最后给几条实在的建议:

  1. 数据量小于 1000 条:用分层 5 折交叉验证。别切固定验证集了,浪费数据。
  2. 数据量 1000-10 万条:切 70/15/15,用分层采样。交叉验证可选,但非必须。
  3. 数据量大于 10 万条:切 80/10/10 甚至 98/1/1。交叉验证计算量太大,不划算。
  4. 类别极度不平衡:必须用分层采样。我曾经处理过一个 99:1 的样本,不用分层的话,验证集里可能一个正样本都没有。
  5. 时间序列:永远不要用普通交叉验证。用 TimeSeriesSplit 或滚动窗口。

我的个人习惯: 不管数据量多大,第一版模型先用分层 5 折交叉验证跑一遍。虽然慢点,但能对模型稳定性有个底。等模型定型了,再切固定测试集做最终评估。

数据集划分这事,看着简单,但细节决定成败。你想想看,如果评估结果本身就不靠谱,后面花再多精力调参也是白搭。嗯,先把地基打牢。

专注资料整理