数据准备篇:数据集划分的黄金法则与交叉验证
做模型训练这几年,我踩过最大的坑,往往不是模型结构设计错了,而是数据划分出了问题。你想想看,模型再牛,如果训练集和验证集混在一起,那评估结果就是自欺欺人。今天咱们聊聊数据集划分这件事,我把自己实战中总结的经验全盘托出。
为什么数据集划分这么重要?
说白了,模型训练的本质就是「学习」和「考试」。训练集是课本,验证集是模拟考,测试集是高考。你要是把高考题提前给学生练了,那成绩再高也是假的。
我在项目中遇到过一件事:有个同事训练了一个分类模型,准确率高达98%。结果上线后直接崩了,实际准确率不到60%。后来一查,原来是数据划分时发生了「数据泄露」——训练集和测试集里混入了同一个用户的不同样本。嗯,这种错误一旦犯过,你就再也不敢马虎了。
数据集划分的黄金法则
我个人习惯把数据划分分成三个层级,每个层级解决不同的问题:
1. 基础划分:训练/验证/测试
最常见的比例是 70%/15%/15% 或 80%/10%/10%。但比例不是死的,关键看数据量:
| 数据总量 | 建议划分比例 | 注意事项 |
|---|---|---|
| < 1万 | 60%/20%/20% | 验证集和测试集不能太少,否则评估不稳定 |
| 1万 - 10万 | 70%/15%/15% | 标准划分,大多数场景适用 |
| 10万 - 100万 | 80%/10%/10% | 数据量足够,验证集可以小一点 |
| > 100万 | 90%/5%/5% | 验证集5%可能就有几万条,足够了 |
2. 分层采样:保持分布一致
随机划分有个大问题——类别分布可能不均匀。比如二分类任务,正样本只占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,
stratify=y, # 按标签分层
random_state=42
)
我曾经因为没做分层采样,导致验证集上模型表现忽高忽低。后来加了 stratify 参数,评估结果一下子就稳定了。你想想看,这行代码能省多少事?
3. 时间序列的特殊处理
如果是时间序列数据,千万别随机划分。为什么?因为未来不能预测过去啊!
正确的做法是按时间顺序划分:
# 按时间排序后,取前70%训练,后30%测试
data = data.sort_values('timestamp')
train = data.iloc[:int(len(data)*0.7)]
test = data.iloc[int(len(data)*0.7):]
交叉验证:小数据集的救星
数据量少的时候,单次划分太浪费了。交叉验证能让你物尽其用。
K折交叉验证
把数据分成K份,每次用K-1份训练,1份验证。循环K次,取平均结果。K通常取5或10。
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
scores = cross_val_score(model, X, y, cv=5)
print(f'平均准确率: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})')
我个人习惯用5折交叉验证。10折虽然更稳定,但计算量翻倍,收益却不大。5折是个很好的平衡点。
留一法(LOO)
极端情况:数据只有几十条。这时候K折都不够用,可以用留一法。每次拿一条做验证,其余全部训练。
但说实话,留一法计算量太大,我只在数据少于50条时才会用。平时还是老老实实用5折。
避坑指南:我踩过的那些坑
这些年我总结了几条血泪教训,分享给你:
- 数据泄露:我曾经把同一个用户的不同会话分到了训练集和测试集。模型记住了用户特征,而不是学习任务本身。解决办法是按用户ID分组后再划分。
- 验证集太小:有一次我图省事,只分了5%做验证。结果模型在验证集上波动很大,根本看不出真实效果。后来我改成15%,问题就解决了。
- 忘记设置随机种子:每次跑结果都不一样,调参时根本没法对比。现在我每个项目都固定 random_state=42。
- 测试集被反复使用:有人用测试集调参,相当于把高考题当练习题做。记住:测试集只能用来做最终评估,一次都不能多用。
- 训练/验证/测试三集独立,互不重叠
- 分层采样保持分布一致
- 时间序列按时间顺序划分
- 小数据集用交叉验证
- 测试集只用一次
知识体系总览
下面这张图概括了数据集划分的核心逻辑,我画了很久才理清楚:
嗯,这张图把整个流程串起来了。从原始数据出发,经过合理划分,到三个集合各司其职。记住这个流程,数据准备这关你就过了大半。
数据划分看起来简单,但真正做好不容易。我见过太多人在这上面栽跟头,包括我自己。希望今天分享的这些经验,能帮你少走一些弯路。