机器学习的数据分片

机器学习中的数据分片,指的是将原始数据集切分成多个互不重叠的子集,用于训练、验证和测试模型。这么做是为了在评估模型效果时,模拟模型从未见过的数据,从而避免"自卖自夸"式的过度乐观评估。

📊 常见分片方法

方法 核心做法 适用场景/要点
留出法 随机将数据分为训练集(约70-80%)和测试集(约20-30%),训练集用于训练,测试集用于最终评估。 数据量较大时简单高效。注意需随机划分,且测试集不能参与任何训练步骤。
K折交叉验证 将数据等分为K份(如5份或10份)。每次取其中1份作测试集,其余K-1份作训练集,重复K次,最终结果取平均值。 数据量较小时,能更充分地利用数据,评估结果更稳定可靠。计算成本也更高。
分层采样 在划分时,保证训练集和测试集中各类别的比例与原始数据一致。 处理类别不平衡数据(如欺诈检测)时的关键步骤,能防止某类样本在某个子集中完全缺失。

⚠️ 核心原则:防止数据泄露

数据分片最重要的原则是:"先分片,后预处理"。

如果先对全量数据做标准化或缺失值填充,再划分训练/测试集,那么测试集的统计信息(如均值、方差)就会"泄露"给模型。这会导致模型在测试集上表现虚高,但在真实场景中失效。正确的流程是在分片后,仅在训练集上计算这些参数,再应用到测试集

以下是上述三种数据分片方法的 scikit-learn 实现代码。为了更直观,我使用一个模拟的二分类数据集来演示。

0. 准备模拟数据

复制代码
import numpy as np
from sklearn.datasets import make_classification

# 生成一个包含1000个样本、20个特征、且类别不平衡(比例约9:1)的数据集
X, y = make_classification(
    n_samples=1000, 
    n_features=20, 
    n_informative=15, 
    n_redundant=5, 
    weights=[0.9, 0.1],  # 类别不平衡
    random_state=42
)
print(f"数据集大小: {X.shape}, 标签分布: {np.bincount(y)}")
复制代码

1. 留出法 (Hold-out)

使用 train_test_split。关键参数是 stratify=y,用于在划分时保持类别比例一致。

复制代码
from sklearn.model_selection import train_test_split

# 第一次划分:训练集 + 临时集(验证集+测试集)
X_train, X_temp, y_train, y_temp = train_test_split(
    X, y, 
    test_size=0.3,       # 临时集占30%
    random_state=42, 
    stratify=y           # 分层采样,保持类别比例
)

# 第二次划分:将临时集拆分为验证集和测试集
X_val, X_test, y_val, y_test = train_test_split(
    X_temp, y_temp, 
    test_size=0.5,       # 验证集和测试集各占一半(即总数据的15%)
    random_state=42, 
    stratify=y_temp
)

print("留出法划分结果:")
print(f"训练集: {X_train.shape[0]} 样本, 标签分布: {np.bincount(y_train)}")
print(f"验证集: {X_val.shape[0]} 样本, 标签分布: {np.bincount(y_val)}")
print(f"测试集: {X_test.shape[0]} 样本, 标签分布: {np.bincount(y_test)}")
复制代码

2. K折交叉验证 (K-Fold Cross-Validation)

使用 KFold 或 StratifiedKFold。对于分类问题,强烈推荐使用 StratifiedKFold 以保证每折的类别比例一致。

复制代码
from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

print("K折交叉验证划分结果(展示每折的验证集大小):")
for fold, (train_index, val_index) in enumerate(skf.split(X, y), 1):
    X_train_fold, X_val_fold = X[train_index], X[val_index]
    y_train_fold, y_va
复制代码

3. 分层采样 (Stratified Sampling)

分层采样的核心逻辑已经包含在 train_test_split(stratify=y) 和 StratifiedKFold 中。下面单独展示一个自定义比例的分层抽样例子,比如从每个类别中按相同比例抽取样本。

复制代码
from sklearn.model_selection import StratifiedShuffleSplit

# StratifiedShuffleSplit 可以指定只划分一次,且支持分层
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)

print("分层采样划分结果:")
for train_index, test_index in sss.split(X, y):
    X_train_strat, X_test_strat = X[train_index], X[test_index]
    y_train_strat, y_test_strat = y[train_index], y[test_index]
    
    print(f"训练集: {X_train_strat.shape[0]} 样本, 标签分布: {np.bincount(y_train_strat)}")
    print(f"测试集: {X_test_strat.shape[0]} 样本, 标签分布: {np.bincount(y_test_strat)}")
    
    # 验证比例是否一致
    train_ratio = np.bincount(y_train_strat) / len(y_train_strat)
    test_ratio = np.bincount(y_test_strat) / len(y_test_strat)
    print(f"训练集类别比例: {train_ratio}")
    print(f"测试集类别比例: {test_ratio}")
复制代码

⚠️ 核心原则:防止数据泄露的正确流程

以下代码演示了错误做法 和正确做法的区别,以标准化(Standardization)为例。

复制代码
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# 划分数据
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# ❌ 错误做法:先对全量数据做标准化,再划分
# scaler_wrong = StandardScaler()
# X_scaled_wrong = scaler_wrong.fit_transform(X)  # 测试集信息泄露到了训练过程中
# X_train_wrong, X_test_wrong, y_train_wrong, y_test_wrong = train_test_split(
#     X_scaled_wrong, y, test_size=0.2, random_state=42
# )

# ✅ 正确做法:先划分,再仅在训练集上 fit 预处理器
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # 只在训练集上计算均值和方差
X_test_scaled = scaler.transform(X_test)        # 用训练集的参数来转换测试集

# 训练模型并评估
model = LogisticRegression(max_iter=1000, class_weight='balanced')
model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled)

print(f"正确流程下的测试集准确率: {accuracy_score(y_test, y_pred):.4f}")
复制代码

总结:

  • 留出法 :train_test_split,记得加 stratify=y。

  • K折交叉验证 :StratifiedKFold,分类问题首选。

  • 分层采样 :train_test_split 或 StratifiedShuffleSplit 的 stratify 参数。

  • 防泄露 :任何预处理(标准化、缺失值填充、PCA等)都必须在划分后,仅用训练集 fit,再 transform 测试集。

相关推荐
Gu_WenYun1 小时前
端侧AI规模化落地,算力景气延续,科技基金怎么选?
人工智能·科技·金融
u1301301 小时前
GitHub 热榜项目:日榜(2026-10-12)
人工智能·github
chien0111 小时前
Agent 需要什么样的运行时?——读阿里云 Agent Sandbox 发布报道
人工智能·语言模型
码流子1 小时前
事件告警延迟拆解:从摄像头到手机通知,延迟卡在哪六个环节
数据库·人工智能·物联网
QYR_111 小时前
全球半导体离子注入机用零部件市场分析:2032年规模有望突破8亿美元,精密制造与高纯材料驱动行业增长
大数据·人工智能
β添砖java1 小时前
深度学习5:循环神经网络:RNN介绍、词嵌入层、循环网络层、文本生成案例
人工智能·rnn·深度学习
爱喝热水的呀哈喽1 小时前
hm探查。
java·前端·人工智能
Q26433650231 小时前
【有源码】基于K-Means算法的航空客户行为分群及异常预订识别研究-基于大数据的航空客户预订行为多维分析与可视化大屏设计
大数据·人工智能·机器学习·数据挖掘·数据分析·spark·kmeans