数据集划分策略:训练集、验证集、测试集的划分原则,分层采样与交叉验证
做模型验证这么多年,我见过太多人在这上面栽跟头。说白了,数据集怎么切,直接决定了你评估出来的精度靠不靠谱。今天咱们就把这事聊透。
一、三大集合:各司其职
先搞清楚三个集合分别干嘛用的。我习惯这么理解:
- 训练集:喂给模型学习的,相当于学生的课本和习题。
- 验证集:调参时用的,相当于模拟考。你调学习率、改网络层数,都得看验证集的表现。
- 测试集:最终大考。模型训练完、参数定好之后,只用这一次。测完就封存,不能再回头改模型。
核心原则:测试集绝对不能参与任何训练决策。 我在项目中遇到过有人不小心把测试集泄露到调参流程里,结果上线后精度直接崩了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 或滚动窗口验证。我曾经在这上面吃过亏,模型在历史数据上表现完美,一上线预测未来就崩了。
六、知识体系总览
下面这张图把整个数据集划分策略串起来了。我建议你保存下来,做项目时对照着看。
七、实战建议
最后给几条实在的建议:
- 数据量小于 1000 条:用分层 5 折交叉验证。别切固定验证集了,浪费数据。
- 数据量 1000-10 万条:切 70/15/15,用分层采样。交叉验证可选,但非必须。
- 数据量大于 10 万条:切 80/10/10 甚至 98/1/1。交叉验证计算量太大,不划算。
- 类别极度不平衡:必须用分层采样。我曾经处理过一个 99:1 的样本,不用分层的话,验证集里可能一个正样本都没有。
- 时间序列:永远不要用普通交叉验证。用 TimeSeriesSplit 或滚动窗口。
我的个人习惯: 不管数据量多大,第一版模型先用分层 5 折交叉验证跑一遍。虽然慢点,但能对模型稳定性有个底。等模型定型了,再切固定测试集做最终评估。
数据集划分这事,看着简单,但细节决定成败。你想想看,如果评估结果本身就不靠谱,后面花再多精力调参也是白搭。嗯,先把地基打牢。