
☞ ░ 前往老猿Python博客 ░ https://blog.youkuaiyun.com/LaoYuanPython
一、概述
在机器学习中,数据预处理是非常重要的工作,常规执行顺序:数据分割 → 2. 数据清洗 → 3. 特征编码 → 4. 特征构造 → 5. 异常值处理 → 6. 特征缩放 → 7. 降维,可以看到数据分割是数据预处理的第一步。
任何基于统计的预处理(如均值填充、标准化)都应仅在训练集上计算参数,再应用到测试集,这样测试集才能起到评估训练后模型的效果。
Scikit-learn 提供了多种数据分割方法,适用于不同机器学习场景,包括简单随机分割train_test_split、标准K折交叉验证KFold、分层K折交叉验证StratifiedKFold、重复多次K折验证RepeatedKFold/RepeatedStratifiedKFold、时间序列分割TimeSeriesSplit、分组分割GroupKFold、LeaveOneGroupOut、留一法LeaveOneOut/LeavePOut。
这些方法一些使用上的建议:
- train_test_split:快速验证的简单随机数据分割
- KFold:适合回归任务,注意大数据集可减少n_splits
- StratifiedKFold:适合数据集不均衡分类 ,分类任务优先使用
- TimeSeriesSplit:适合时间序列
- GroupKFold:适合分组数据
- LeaveOneOut:适合小数据集
- RepeatedKFold:适合结果不稳定时使用
这些方法都可通过sklearn.model_selection导入,是模型评估的重要工具。根据数据特性和任务需求选择合适的分割方式,能显著提高模型评估的可靠性。
二、简单随机数据分割train_test_split
任何基于统计的预处理(如均值填充、标准化)都应仅在训练集上计算参数,再应用到测试集,这样测试集才能起到评估训练后模型的效果。
为了将数据集划分成训练集和测试集,sklearn提供了简单随机分割train_test_split方法,train_test_split 是 scikit-learn 中一个非常实用的函数,用于将数据集随机划分为训练集和测试集,是机器学习中数据准备阶段的常用工具。
主要参数:
- arrays: 需要分割的数据集(可以是多个数组),通常是特征数据和标签数据。多个输入数据集(arrays)的样本数必须相同,但每个数据集本身的形状(特征维度)可以不同。多个数据集在分割后,训练集和测试集中的样本会保持严格的对应关系(即相同位置的样本来自原始数据的同一行)
- test_size: 测试集比例或数量,可以是 float (0.0-1.0,表示测试集数据数量占分割前数据的比例) 或 int(表示测试集中样本的绝对数量,必须小于总样本数,test_size=30 表示测试集将包含 30 个样本)
- train_size: 训练集比例或数量,与 test_size 互补,通常只需指定一个,如果同时设置了 train_size 和 test_size,它们的和必须小于等于总样本数
- random_state: 随机种子,相同的值用于重现相同的分割结果
- shuffle: 是否在分割前打乱数据,默认为 True
- stratify: 分类的标签(如对于分类问题直接传入目标变量 y),默认值为None(关闭分层抽样,完全随机分割),用于分层抽样,按指定数组的类别比例进行分层分割,常用于分类问题,确保训练集和测试集中的类别比例与原始数据集保持一致,用于保持类别分布、避免类别不平衡问题,以提高评估可靠性。当 shuffle=False 时不能使用 stratify,因为此时数据会严格按照原始顺序分割,就无法保障分类比例。
案例:
from sklearn.model_selection import train_test_split
import numpy as np
X1,X2,X3 = np.array(([1,2,3,4,5,6],['A','B','C','D','E','F'],['a','b','c','d','e','f']))
x10,x11,x20,x21,x30,x31 = train_test_split(X1,X2,X3,train_size=0.5)
print(x10,x20,x30,x11,x21,x31,sep='\n')
输出结果如下:
['6' '1' '2']
['F' 'A' 'B']
['f' 'a' 'b']
['5' '4' '3']
['E' 'D' 'C']
['e' 'd' 'c']
可以看到前3行相同列对应数据都是分割前数据同一列的,后3行相同列对应数据都是分割前数据同一列的。
可以看到train_test_split除了支持简单随机分割,也可以支持分类按比例分割。
三、K折交叉验证KFold
K折交叉验证将数据集 均匀分割 为 K 个互斥的子集(称为“折”,folds),每折大小大致相同。每次迭代中,1折作为验证集,剩余 K-1 折作为训练集,共进行 K 次训练和验证,最终模型的性能是 K 次验证结果的平均值。
K折交叉验证适用于回归任务和类别类别分布均衡的分类任务。
sklearn中的K折交叉验证使用KFold类实现,其初始化参数如下:
- n_splits:分割的折数 K(必须 ≥ 2),整型,默认值5,推荐值5 或 10(平衡计算成本和评估可靠性)。若设为 n_splits=5,则生成 5 折,训练集占 80%,验证集占 20%。对小数据集可增加折数(如 n_splits=10)以提高评估稳定性,对大数据集减少折数(如 n_splits=3)以降低计算成本;
- shuffle: 是否在分割前打乱数据顺序,布尔型,默认值False,表示按数据原始顺序分割(适用于时间序列以外的场景),为True则先打乱数据再分割(避免因原始顺序引入偏差);
- random_state:随机种子(仅当 shuffle=True 时生效),整型,默认值为None,固定随机种子为某个数值可确保每次运行结果一致
在 Scikit-learn 的 KFold 交叉验证中,数据划分遵循一套明确的规则来确保每个样本都被公平地用于训练和验证。
假设样本数为N折数为K,其划分逻辑如下:
- 如果 N 能被 K 整除:每折验证集包含 N/K 个样本。
- 如果 N 不能被 K 整除:前 N % K 折的验证集的样本数为N/K向下取整+1 个样本,后面其余折的验证集样本数为N/K向下取整。
创建的KFold类对象,其方法split用于获取生成的训练集和验证集的数据索引。
分割数据的案例:
from sklearn.model_selection import KFold
import numpy as np
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
y = np.array([0, 1, 0, 1, 0])
# 初始化 KFold(3折,打乱数据)
kf = KFold(n_splits=3, shuffle=True, random_state=292)
print(type(kf))
# 获取每折的索引
for train_idx, test_idx in kf.split(X):
print("Train:", train_idx, "Test:", test_idx)
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
输出值如下:
<class 'sklearn.model_selection._split.KFold'>
Train: [2 3 4] Test: [0 1]
Train: [0 1 4] Test: [2 3]
Train: [0 1 2 3] Test: [4]
用于训练和验证的案例:
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import numpy as np
# 示例数据(特征X和标签y)
X = np.array([[i,i+1] for i in range(100)])
y = np.array([int(i/10) for i in range(100)]) # 二分类标签
# 初始化模型
model = RandomForestClassifier(random_state=20209)
# 初始化 KFold(3折,打乱数据)
kf = KFold(n_splits=10 ,shuffle=True, random_state=20209)
# 存储每折的准确率
accuracies = []
for fold, (train_idx, val_idx) in enumerate(kf.split(X, y), 1):
# 分割数据
X_train, X_val = X[train_idx], X[val_idx]
y_train, y_val = y[train_idx], y[val_idx]
# 训练模型
model.fit(X_train, y_train)
# 验证模型
y_pred = model.predict(X_val)
acc = accuracy_score(y_val, y_pred)
accuracies.append(acc)
# 打印当前折结果
print(f"Fold {fold}: Accuracy = {acc:.2f}")
# 输出平均性能
print(f"\nMean Accuracy: {np.mean(accuracies):.2f} ± {np.std(accuracies):.2f}")
输出数据如下:
Fold 1: Accuracy = 0.80
Fold 2: Accuracy = 0.80
Fold 3: Accuracy = 1.00
Fold 4: Accuracy = 0.90
Fold 5: Accuracy = 0.90
Fold 6: Accuracy = 1.00
Fold 7: Accuracy = 0.90
Fold 8: Accuracy = 0.80
Fold 9: Accuracy = 1.00
Fold 10: Accuracy = 1.00
Mean Accuracy: 0.91 ± 0.08
四、小结
本文简单介绍了机器学习中的数据分割经常使用的方法,并具体介绍了sklearn中简单随机分割train_test_split、标准K折交叉验证KFold两种具体方法及其使用案例,后续文章将介绍其他几种数据分割方法。需要注意任何基于统计的预处理(如均值填充、标准化)都应仅在训练集上计算参数,再应用到测试集,这样测试集才能起到评估训练后模型的效果。
更多人工智能知识学习过程中可能遇到的疑难问题及解决办法请关注专栏《零基础机器学习入门》及付费专栏《机器学习疑难问题集》后续的文章。
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
关于老猿的付费专栏
- 付费专栏《https://blog.youkuaiyun.com/laoyuanpython/category_9607725.html 使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,对应文章目录为《 https://blog.youkuaiyun.com/LaoYuanPython/article/details/107580932 使用PyQt开发图形界面Python应用专栏目录》;
- 付费专栏《https://blog.youkuaiyun.com/laoyuanpython/category_10232926.html moviepy音视频开发专栏 )详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,对应文章目录为《https://blog.youkuaiyun.com/LaoYuanPython/article/details/107574583 moviepy音视频开发专栏文章目录》;
- 付费专栏《https://blog.youkuaiyun.com/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》为《https://blog.youkuaiyun.com/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的伴生专栏,是笔者对OpenCV-Python图形图像处理学习中遇到的一些问题个人感悟的整合,相关资料基本上都是老猿反复研究的成果,有助于OpenCV-Python初学者比较深入地理解OpenCV,对应文章目录为《https://blog.youkuaiyun.com/LaoYuanPython/article/details/109713407 OpenCV-Python初学者疑难问题集专栏目录 》
- 付费专栏《https://blog.youkuaiyun.com/laoyuanpython/category_10762553.html Python爬虫入门 》站在一个互联网前端开发小白的角度介绍爬虫开发应知应会内容,包括爬虫入门的基础知识,以及爬取优快云文章信息、博主信息、给文章点赞、评论等实战内容。
前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.youkuaiyun.com/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.youkuaiyun.com/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。