1. 项目概述为什么数据集拆分是机器学习的第一步如果你刚开始接触机器学习可能会觉得最激动人心的部分是选择酷炫的模型比如随机森林或者神经网络。但作为一个踩过无数坑的老手我得告诉你真正决定项目成败的往往是在模型训练之前一个看似简单却至关重要的步骤如何正确地拆分你的数据集。今天我们就来深入聊聊scikit-learn中的train_test_split()函数这可能是你机器学习工具箱里使用频率最高却也最容易用错的工具之一。想象一下你费尽心思训练了一个模型在训练数据上表现近乎完美准确率高达99%。你满怀信心地把它部署到真实世界结果却一塌糊涂。这种尴尬的局面十有八九是因为模型“死记硬背”了训练数据的所有细节包括噪声而丧失了泛化到新数据的能力这就是臭名昭著的过拟合。而train_test_split()的核心使命就是通过创建一个独立的“考试卷”——测试集来提前发现并防止这种情况。它把你的原始数据一分为二一部分用于“教学”训练集让模型学习规律另一部分用于“期末考试”测试集来公正地评估模型学得怎么样。这个简单的动作是构建可靠、可信机器学习模型的基石。2.train_test_split()的核心原理与关键参数深度解析2.1 随机性背后的科学与random_state参数train_test_split()最基本的使用看起来很简单X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2)。但这行代码里藏着一个“暗箱”随机性。函数默认会随机打乱数据顺序然后按比例切割。这里的“随机”是好事它确保了数据分布的均匀性但也是坏事的源头——结果不可复现。你今天跑一遍得到一个准确率85%的模型。明天同样的代码再跑一遍可能就变成83%了。这是因为两次的数据拆分结果不同。对于实验、论文或者需要团队协作的项目这种不确定性是灾难性的。这就是random_state参数存在的意义。你可以把它理解为一个随机数生成器的“种子”。设置一个固定的整数值比如random_state42这是机器学习社区的一个神秘传统数字就能确保每次运行代码时数据的拆分方式完全一致从而得到可复现的结果。注意random_state保证了单次运行的可复现性但它并不影响模型的泛化能力评估的稳定性。要获得更稳健的模型性能估计我们还需要后续要讲的交叉验证。2.2 拆分比例的艺术test_size与train_sizetest_size0.2意味着20%的数据留作测试这是最常见的选择。但这个比例并非金科玉律它需要根据你的数据总量和具体任务来权衡。大数据集10万样本测试集比例可以小一些比如5%或10%。因为即使5%也有5000个样本用于评估通常已经能提供足够可靠的性能估计同时能让模型在更多的数据95%上训练。小数据集1万样本这时需要谨慎。测试集比例太小如10%可能只有几百个测试样本评估结果方差会很大不够可靠。比例太大如40%又会挤占宝贵的训练数据导致模型因为“学得少”而表现不佳。一个常见的折中是维持20%-30%或者采用交叉验证。train_size参数你也可以直接指定训练集的大小如train_size8000或train_size0.8。注意test_size和train_size只需指定一个另一个会自动计算。如果两个都指定它们的和必须为1.0或总样本数。2.3 保持数据关联shuffle与stratify参数shuffleTrue(默认)在拆分前打乱数据。这至关重要尤其是当你的原始数据是按某种顺序排列的时候例如按时间顺序收集的数据前一半都是A类后一半都是B类。如果不打乱你的训练集可能全是A类测试集全是B类模型将完全无法泛化。只有在数据本身就是独立同分布且顺序无关紧要的极少数情况下才考虑设为False。stratify参数分类任务救星这是我最想强调的一个高级技巧。假设你有一个分类数据集其中90%是“猫”的图片10%是“狗”的图片类别不平衡。如果进行普通的随机拆分有可能你的训练集中“狗”的图片只占8%而测试集中却占了15%。这样模型在“狗”这个类别上的训练就不充分评估也会有偏差。 将stratify参数设置为你的目标标签y即stratifyytrain_test_split()会进行分层抽样。它能确保拆分后的训练集和测试集中各个类别的比例与原始数据集中的比例完全一致。这能显著提高模型评估的公平性和可靠性特别是在处理类别不平衡的数据时这是必须使用的参数。3. 从基础到进阶多种场景下的拆分实战3.1 基础单输入输出拆分这是最标准的场景适用于绝大多数监督学习任务。from sklearn.model_selection import train_test_split import pandas as pd from sklearn.datasets import load_iris # 加载示例数据 iris load_iris() X iris.data # 特征矩阵 y iris.target # 目标标签 # 基础拆分设置 random_state 保证可复现stratify 保证类别分布 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy # 对于分类任务强烈建议使用 ) print(f训练集形状: {X_train.shape}, 测试集形状: {X_test.shape}) print(f训练集类别分布: {pd.Series(y_train).value_counts().to_dict()}) print(f测试集类别分布: {pd.Series(y_test).value_counts().to_dict()})运行后你会发现训练集和测试集中每个类别的样本数比例都完美保持了原始数据原始数据每个类别50个训练集每个类别40个测试集每个类别10个。3.2 处理多个输入数组如同时拆分特征与ID有时你的数据不止X和y。例如你还有一个包含样本ID或时间戳的数组需要在拆分时保持与特征和标签的对应关系。train_test_split()可以接受多个数组并按相同的方式对它们进行拆分。import numpy as np # 假设我们还有样本ID数组 sample_ids np.arange(len(X)) # 生成0,1,2,...的ID # 同时拆分特征X、标签y和样本ID X_train, X_test, y_train, y_test, id_train, id_test train_test_split( X, y, sample_ids, # 传入多个数组 test_size0.25, random_state42, stratifyy ) # 现在你可以通过 id_train 和 id_test 追溯到原始数据中的具体样本 print(f测试集前5个样本的ID: {id_test[:5]})3.3 与Pandas DataFrame无缝协作实际项目中数据通常以Pandas DataFrame形式存在。我们需要小心地从DataFrame中提取特征和标签。import pandas as pd from sklearn.datasets import make_regression # 生成一个回归问题的示例DataFrame X_df, y_series make_regression(n_samples1000, n_features5, noise0.1, random_state42) df pd.DataFrame(X_df, columns[ffeature_{i} for i in range(5)]) df[target] y_series # 定义特征列和目标列 feature_cols [ffeature_{i} for i in range(5)] target_col target X df[feature_cols] y df[target_col] # 进行拆分 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 # 回归任务通常不需要 stratify ) # 此时 X_train, X_test 仍然是DataFrame保留了列名信息便于后续分析和调试 print(fX_train 列名: {X_train.columns.tolist()})实操心得始终明确地将特征列和目标列分开赋值给X和y再进行拆分。避免直接在train_test_split中传入整个DataFrame和列索引切片这样代码更清晰也不容易出错。4. 超越简单拆分为什么需要验证集与交叉验证4.1 训练集、验证集、测试集的“三国演义”只用train_test_split分成两部分训练集、测试集有一个潜在问题模型调参的过程会“污染”测试集。当你基于测试集上的表现来调整模型参数如决策树的深度、正则化强度时测试集实际上已经参与了“训练”它不再是完全独立的评估基准。这会导致你对模型泛化能力的估计过于乐观。更严谨的做法是引入验证集形成三部分训练集用于模型训练。验证集用于模型调参、选择模型和早期停止。你可以在这上面尝试不同的超参数看哪个效果好。测试集在最终模型和参数确定后仅使用一次用于提供模型泛化性能的无偏估计。它就像高考在考前绝对不能泄露。如何实现可以连续调用两次train_test_split。# 第一步先分出临时训练集后续用于训练验证和最终的测试集 X_temp, X_test, y_temp, y_test train_test_split( X, y, test_size0.2, # 20% 作为最终测试集 random_state42, stratifyy ) # 第二步从临时训练集中再分出一部分作为验证集 # 注意此时 X_temp 占原始数据的80%我们从中再拿出 25% 作为验证集。 # 80% * 25% 20% 的原始数据作为验证集。 # 最终比例训练集60%验证集20%测试集20%。 X_train, X_val, y_train, y_val train_test_split( X_temp, y_temp, test_size0.25, # 占 X_temp 的25%即占总体的20% random_state42, stratifyy_temp ) print(f最终划分训练集{X_train.shape}验证集{X_val.shape}测试集{X_test.shape})4.2 更稳健的评估K折交叉验证K-Fold CV当数据量不大时单次的训练/验证/测试划分可能因为随机性导致评估结果不稳定。K折交叉验证是更强大的工具。它将训练数据分成K个大小相似的“折”fold然后进行K轮训练和验证。每一轮使用其中一折作为验证集其余K-1折作为训练集。最后将K轮验证结果的平均值作为模型性能的估计。虽然train_test_split不直接做交叉验证但理解它能帮你更好地使用scikit-learn中的cross_val_score或KFold。from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression # 使用最初的训练集 X_train, y_train (占原始数据60%) model LogisticRegression(max_iter200) # 进行5折交叉验证评估指标为准确率 cv_scores cross_val_score(model, X_train, y_train, cv5, scoringaccuracy) print(f5折交叉验证准确率: {cv_scores}) print(f平均准确率: {cv_scores.mean():.4f} (/- {cv_scores.std()*2:.4f}))交叉验证的均值给出了更稳健的性能估计标准差反映了估计的稳定性。这个过程完全在训练集或我们之前的X_temp内进行没有动用测试集。5. 实战避坑指南与高级技巧5.1 时间序列数据的特殊处理对于时间序列数据如股票价格、每日销售额绝对不能使用随机拆分因为未来的数据不能用于预测过去。必须按时间顺序拆分。# 假设 df 是一个按时间排序的DataFramedate 是日期列 df_sorted df.sort_values(date) # 确定一个时间点作为切割点 split_point int(len(df_sorted) * 0.8) # 前80%的时间段用于训练 X df_sorted.drop(target, axis1) y df_sorted[target] # 按索引切割 X_train, X_test X.iloc[:split_point], X.iloc[split_point:] y_train, y_test y.iloc[:split_point], y.iloc[split_point:] # 此时应设置 shuffleFalse但因为我们已手动按时间分割所以不需要再调用 train_test_split5.2 数据泄漏一个毁灭性的错误数据泄漏是指测试集的信息在训练阶段被模型以某种方式“看到”了。这会导致评估结果虚高但模型在实际中完全失效。常见的泄漏场景包括全局标准化先在整个数据集包括未来测试集上计算均值和标准差再进行拆分和标准化。正确做法是只在训练集上计算标准化参数均值和标准差然后用这些参数去转换训练集和测试集。使用未来信息在时间序列中使用了未来的数据来预测过去。目标变量相关特征特征中包含了直接或间接指向目标的信息。例如在预测房价的任务中特征里包含了“最终成交价”的衍生变量。使用train_test_split的第一步就进行拆分然后在后续的预处理管道中严格区分训练集和测试集是防止数据泄漏的最佳实践。5.3 与Pipeline结合实现安全流程将train_test_split与scikit-learn的Pipeline和ColumnTransformer结合可以构建一个安全、自动化的机器学习流程有效防止数据泄漏。from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.impute import SimpleImputer # 假设我们有数值型和分类型特征 numeric_features [age, income] categorical_features [city, job_type] # 为不同类型特征创建预处理管道 numeric_transformer Pipeline(steps[ (imputer, SimpleImputer(strategymedian)), # 填充缺失值 (scaler, StandardScaler()) # 标准化 ]) categorical_transformer Pipeline(steps[ (imputer, SimpleImputer(strategyconstant, fill_valuemissing)), (onehot, OneHotEncoder(handle_unknownignore)) # 独热编码 ]) # 组合成一个完整的预处理器 preprocessor ColumnTransformer( transformers[ (num, numeric_transformer, numeric_features), (cat, categorical_transformer, categorical_features) ]) # 创建包含预处理和模型的完整管道 from sklearn.ensemble import RandomForestClassifier clf Pipeline(steps[ (preprocessor, preprocessor), (classifier, RandomForestClassifier(random_state42)) ]) # 拆分数据 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 训练管道preprocessor 只在 X_train 上拟合然后转换 X_train 和 X_test clf.fit(X_train, y_train) # 评估整个过程测试集数据从未在拟合阶段被使用 score clf.score(X_test, y_test) print(f模型在测试集上的准确率: {score:.4f})这个流程确保了所有基于数据的计算如计算缺失值填充值、标准化均值标准差、独热编码的类别都仅在训练集上完成然后被应用于测试集完美规避了数据泄漏的风险。掌握train_test_split远不止是记住一个函数调用。它关乎你如何严谨地对待数据如何设计可靠的实验流程以及最终如何交付一个真正能在现实世界中发挥作用的模型。从设置好random_state和stratify开始到理解验证集的意义再到警惕数据泄漏并与Pipeline结合每一步都是在为你的机器学习项目打下坚实可靠的基础。
机器学习数据拆分实战:从train_test_split到防泄漏全流程
发布时间:2026/6/4 12:44:41
1. 项目概述为什么数据集拆分是机器学习的第一步如果你刚开始接触机器学习可能会觉得最激动人心的部分是选择酷炫的模型比如随机森林或者神经网络。但作为一个踩过无数坑的老手我得告诉你真正决定项目成败的往往是在模型训练之前一个看似简单却至关重要的步骤如何正确地拆分你的数据集。今天我们就来深入聊聊scikit-learn中的train_test_split()函数这可能是你机器学习工具箱里使用频率最高却也最容易用错的工具之一。想象一下你费尽心思训练了一个模型在训练数据上表现近乎完美准确率高达99%。你满怀信心地把它部署到真实世界结果却一塌糊涂。这种尴尬的局面十有八九是因为模型“死记硬背”了训练数据的所有细节包括噪声而丧失了泛化到新数据的能力这就是臭名昭著的过拟合。而train_test_split()的核心使命就是通过创建一个独立的“考试卷”——测试集来提前发现并防止这种情况。它把你的原始数据一分为二一部分用于“教学”训练集让模型学习规律另一部分用于“期末考试”测试集来公正地评估模型学得怎么样。这个简单的动作是构建可靠、可信机器学习模型的基石。2.train_test_split()的核心原理与关键参数深度解析2.1 随机性背后的科学与random_state参数train_test_split()最基本的使用看起来很简单X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2)。但这行代码里藏着一个“暗箱”随机性。函数默认会随机打乱数据顺序然后按比例切割。这里的“随机”是好事它确保了数据分布的均匀性但也是坏事的源头——结果不可复现。你今天跑一遍得到一个准确率85%的模型。明天同样的代码再跑一遍可能就变成83%了。这是因为两次的数据拆分结果不同。对于实验、论文或者需要团队协作的项目这种不确定性是灾难性的。这就是random_state参数存在的意义。你可以把它理解为一个随机数生成器的“种子”。设置一个固定的整数值比如random_state42这是机器学习社区的一个神秘传统数字就能确保每次运行代码时数据的拆分方式完全一致从而得到可复现的结果。注意random_state保证了单次运行的可复现性但它并不影响模型的泛化能力评估的稳定性。要获得更稳健的模型性能估计我们还需要后续要讲的交叉验证。2.2 拆分比例的艺术test_size与train_sizetest_size0.2意味着20%的数据留作测试这是最常见的选择。但这个比例并非金科玉律它需要根据你的数据总量和具体任务来权衡。大数据集10万样本测试集比例可以小一些比如5%或10%。因为即使5%也有5000个样本用于评估通常已经能提供足够可靠的性能估计同时能让模型在更多的数据95%上训练。小数据集1万样本这时需要谨慎。测试集比例太小如10%可能只有几百个测试样本评估结果方差会很大不够可靠。比例太大如40%又会挤占宝贵的训练数据导致模型因为“学得少”而表现不佳。一个常见的折中是维持20%-30%或者采用交叉验证。train_size参数你也可以直接指定训练集的大小如train_size8000或train_size0.8。注意test_size和train_size只需指定一个另一个会自动计算。如果两个都指定它们的和必须为1.0或总样本数。2.3 保持数据关联shuffle与stratify参数shuffleTrue(默认)在拆分前打乱数据。这至关重要尤其是当你的原始数据是按某种顺序排列的时候例如按时间顺序收集的数据前一半都是A类后一半都是B类。如果不打乱你的训练集可能全是A类测试集全是B类模型将完全无法泛化。只有在数据本身就是独立同分布且顺序无关紧要的极少数情况下才考虑设为False。stratify参数分类任务救星这是我最想强调的一个高级技巧。假设你有一个分类数据集其中90%是“猫”的图片10%是“狗”的图片类别不平衡。如果进行普通的随机拆分有可能你的训练集中“狗”的图片只占8%而测试集中却占了15%。这样模型在“狗”这个类别上的训练就不充分评估也会有偏差。 将stratify参数设置为你的目标标签y即stratifyytrain_test_split()会进行分层抽样。它能确保拆分后的训练集和测试集中各个类别的比例与原始数据集中的比例完全一致。这能显著提高模型评估的公平性和可靠性特别是在处理类别不平衡的数据时这是必须使用的参数。3. 从基础到进阶多种场景下的拆分实战3.1 基础单输入输出拆分这是最标准的场景适用于绝大多数监督学习任务。from sklearn.model_selection import train_test_split import pandas as pd from sklearn.datasets import load_iris # 加载示例数据 iris load_iris() X iris.data # 特征矩阵 y iris.target # 目标标签 # 基础拆分设置 random_state 保证可复现stratify 保证类别分布 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy # 对于分类任务强烈建议使用 ) print(f训练集形状: {X_train.shape}, 测试集形状: {X_test.shape}) print(f训练集类别分布: {pd.Series(y_train).value_counts().to_dict()}) print(f测试集类别分布: {pd.Series(y_test).value_counts().to_dict()})运行后你会发现训练集和测试集中每个类别的样本数比例都完美保持了原始数据原始数据每个类别50个训练集每个类别40个测试集每个类别10个。3.2 处理多个输入数组如同时拆分特征与ID有时你的数据不止X和y。例如你还有一个包含样本ID或时间戳的数组需要在拆分时保持与特征和标签的对应关系。train_test_split()可以接受多个数组并按相同的方式对它们进行拆分。import numpy as np # 假设我们还有样本ID数组 sample_ids np.arange(len(X)) # 生成0,1,2,...的ID # 同时拆分特征X、标签y和样本ID X_train, X_test, y_train, y_test, id_train, id_test train_test_split( X, y, sample_ids, # 传入多个数组 test_size0.25, random_state42, stratifyy ) # 现在你可以通过 id_train 和 id_test 追溯到原始数据中的具体样本 print(f测试集前5个样本的ID: {id_test[:5]})3.3 与Pandas DataFrame无缝协作实际项目中数据通常以Pandas DataFrame形式存在。我们需要小心地从DataFrame中提取特征和标签。import pandas as pd from sklearn.datasets import make_regression # 生成一个回归问题的示例DataFrame X_df, y_series make_regression(n_samples1000, n_features5, noise0.1, random_state42) df pd.DataFrame(X_df, columns[ffeature_{i} for i in range(5)]) df[target] y_series # 定义特征列和目标列 feature_cols [ffeature_{i} for i in range(5)] target_col target X df[feature_cols] y df[target_col] # 进行拆分 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 # 回归任务通常不需要 stratify ) # 此时 X_train, X_test 仍然是DataFrame保留了列名信息便于后续分析和调试 print(fX_train 列名: {X_train.columns.tolist()})实操心得始终明确地将特征列和目标列分开赋值给X和y再进行拆分。避免直接在train_test_split中传入整个DataFrame和列索引切片这样代码更清晰也不容易出错。4. 超越简单拆分为什么需要验证集与交叉验证4.1 训练集、验证集、测试集的“三国演义”只用train_test_split分成两部分训练集、测试集有一个潜在问题模型调参的过程会“污染”测试集。当你基于测试集上的表现来调整模型参数如决策树的深度、正则化强度时测试集实际上已经参与了“训练”它不再是完全独立的评估基准。这会导致你对模型泛化能力的估计过于乐观。更严谨的做法是引入验证集形成三部分训练集用于模型训练。验证集用于模型调参、选择模型和早期停止。你可以在这上面尝试不同的超参数看哪个效果好。测试集在最终模型和参数确定后仅使用一次用于提供模型泛化性能的无偏估计。它就像高考在考前绝对不能泄露。如何实现可以连续调用两次train_test_split。# 第一步先分出临时训练集后续用于训练验证和最终的测试集 X_temp, X_test, y_temp, y_test train_test_split( X, y, test_size0.2, # 20% 作为最终测试集 random_state42, stratifyy ) # 第二步从临时训练集中再分出一部分作为验证集 # 注意此时 X_temp 占原始数据的80%我们从中再拿出 25% 作为验证集。 # 80% * 25% 20% 的原始数据作为验证集。 # 最终比例训练集60%验证集20%测试集20%。 X_train, X_val, y_train, y_val train_test_split( X_temp, y_temp, test_size0.25, # 占 X_temp 的25%即占总体的20% random_state42, stratifyy_temp ) print(f最终划分训练集{X_train.shape}验证集{X_val.shape}测试集{X_test.shape})4.2 更稳健的评估K折交叉验证K-Fold CV当数据量不大时单次的训练/验证/测试划分可能因为随机性导致评估结果不稳定。K折交叉验证是更强大的工具。它将训练数据分成K个大小相似的“折”fold然后进行K轮训练和验证。每一轮使用其中一折作为验证集其余K-1折作为训练集。最后将K轮验证结果的平均值作为模型性能的估计。虽然train_test_split不直接做交叉验证但理解它能帮你更好地使用scikit-learn中的cross_val_score或KFold。from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression # 使用最初的训练集 X_train, y_train (占原始数据60%) model LogisticRegression(max_iter200) # 进行5折交叉验证评估指标为准确率 cv_scores cross_val_score(model, X_train, y_train, cv5, scoringaccuracy) print(f5折交叉验证准确率: {cv_scores}) print(f平均准确率: {cv_scores.mean():.4f} (/- {cv_scores.std()*2:.4f}))交叉验证的均值给出了更稳健的性能估计标准差反映了估计的稳定性。这个过程完全在训练集或我们之前的X_temp内进行没有动用测试集。5. 实战避坑指南与高级技巧5.1 时间序列数据的特殊处理对于时间序列数据如股票价格、每日销售额绝对不能使用随机拆分因为未来的数据不能用于预测过去。必须按时间顺序拆分。# 假设 df 是一个按时间排序的DataFramedate 是日期列 df_sorted df.sort_values(date) # 确定一个时间点作为切割点 split_point int(len(df_sorted) * 0.8) # 前80%的时间段用于训练 X df_sorted.drop(target, axis1) y df_sorted[target] # 按索引切割 X_train, X_test X.iloc[:split_point], X.iloc[split_point:] y_train, y_test y.iloc[:split_point], y.iloc[split_point:] # 此时应设置 shuffleFalse但因为我们已手动按时间分割所以不需要再调用 train_test_split5.2 数据泄漏一个毁灭性的错误数据泄漏是指测试集的信息在训练阶段被模型以某种方式“看到”了。这会导致评估结果虚高但模型在实际中完全失效。常见的泄漏场景包括全局标准化先在整个数据集包括未来测试集上计算均值和标准差再进行拆分和标准化。正确做法是只在训练集上计算标准化参数均值和标准差然后用这些参数去转换训练集和测试集。使用未来信息在时间序列中使用了未来的数据来预测过去。目标变量相关特征特征中包含了直接或间接指向目标的信息。例如在预测房价的任务中特征里包含了“最终成交价”的衍生变量。使用train_test_split的第一步就进行拆分然后在后续的预处理管道中严格区分训练集和测试集是防止数据泄漏的最佳实践。5.3 与Pipeline结合实现安全流程将train_test_split与scikit-learn的Pipeline和ColumnTransformer结合可以构建一个安全、自动化的机器学习流程有效防止数据泄漏。from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.impute import SimpleImputer # 假设我们有数值型和分类型特征 numeric_features [age, income] categorical_features [city, job_type] # 为不同类型特征创建预处理管道 numeric_transformer Pipeline(steps[ (imputer, SimpleImputer(strategymedian)), # 填充缺失值 (scaler, StandardScaler()) # 标准化 ]) categorical_transformer Pipeline(steps[ (imputer, SimpleImputer(strategyconstant, fill_valuemissing)), (onehot, OneHotEncoder(handle_unknownignore)) # 独热编码 ]) # 组合成一个完整的预处理器 preprocessor ColumnTransformer( transformers[ (num, numeric_transformer, numeric_features), (cat, categorical_transformer, categorical_features) ]) # 创建包含预处理和模型的完整管道 from sklearn.ensemble import RandomForestClassifier clf Pipeline(steps[ (preprocessor, preprocessor), (classifier, RandomForestClassifier(random_state42)) ]) # 拆分数据 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 训练管道preprocessor 只在 X_train 上拟合然后转换 X_train 和 X_test clf.fit(X_train, y_train) # 评估整个过程测试集数据从未在拟合阶段被使用 score clf.score(X_test, y_test) print(f模型在测试集上的准确率: {score:.4f})这个流程确保了所有基于数据的计算如计算缺失值填充值、标准化均值标准差、独热编码的类别都仅在训练集上完成然后被应用于测试集完美规避了数据泄漏的风险。掌握train_test_split远不止是记住一个函数调用。它关乎你如何严谨地对待数据如何设计可靠的实验流程以及最终如何交付一个真正能在现实世界中发挥作用的模型。从设置好random_state和stratify开始到理解验证集的意义再到警惕数据泄漏并与Pipeline结合每一步都是在为你的机器学习项目打下坚实可靠的基础。