机器学习的数据分片

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

📊 常见分片方法

方法 核心做法 适用场景/要点
留出法 随机将数据分为训练集(约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 测试集。

相关推荐
BioTender几秒前
Hugging Face 发布 Carbon-X:一个能够直接理解 DNA 的大语言模型
人工智能·语言模型·自然语言处理
Star(up up up)3 分钟前
Docker系列---Dockerfile镜像文件
人工智能·经验分享·学习·程序人生·docker·容器·github
也非非也5 分钟前
iPhone 中国区 AI 落地:Apple 与阿里千问合作的技术观察
大数据·人工智能·ios·agent·iphone·智子
阡陌数智5 分钟前
通过特化小型语言模型的词表将推理成本降低百分之七十七
人工智能·语言模型·自然语言处理
程序猿编码8 分钟前
RK3588 NPU LLM 推理引擎:自研底层算子,性能碾压原厂 SDK
机器学习·llm·rk3588·大模型推理
January120710 分钟前
【AI方法笔记】2026-11-02:模型流式吐 JSON 时,前端会遇到四种崩法
前端·人工智能·笔记·json
集芯微电科技有限公司11 分钟前
40V/24A高频率增强型GaN HEMT功率开关管/高频DC转换/电动工具/GaN充电器 方案首选
人工智能·科技·单片机·嵌入式硬件·深度学习·神经网络·生成对抗网络
CC数分11 分钟前
统计学基础|先把问题问对:数据分析的六大类型
大数据·人工智能·算法
Elastic 中国社区官方博客13 分钟前
基于 Elasticsearch 与 Jina AI 的全模态智能搜索实践:技术全解析
大数据·人工智能·elasticsearch·搜索引擎·ai·信息可视化·jina
xiaoyunxuexibiji16 分钟前
国资国企采购穿透式监管建设方案:运营体系、部署模式与智能应用
人工智能