ADVANCE Day23

@浙大疏锦行

📘 Day 23 实战作业:机器学习工程化 ------ Pipeline 管道流

1. 作业综述

核心目标

本作业旨在将机器学习工作流从"手动脚本"升级为"工业级管道"。我们将利用 sklearn.pipeline 模块,将数据清洗(缺失值填充)、特征处理(编码、标准化)与模型训练封装为一个原子对象。

为什么要使用 Pipeline?

在之前的作业中,我们在数据预处理时往往需要手动执行 fillna -> map/get_dummies -> StandardScaler。这种分散的操作在实际工程中存在巨大隐患:

  1. 数据泄露 (Data Leakage):如果在整个数据集上做标准化再切分,测试集的信息就泄露到了训练集中。Pipeline 能确保预处理参数(如均值、方差)只从训练集学习,并正确应用到测试集。
  2. 代码复用性差:针对新数据,需要重新写一遍清洗逻辑。Pipeline 可以直接保存并复用。
  3. 调参困难:无法在一个搜索空间内同时调整预处理参数(如 PCA 维度)和模型参数(如 树的数量)。

本作业关键技术点

  • Pipeline: 串联处理步骤。
  • ColumnTransformer: 针对不同列(数值/分类)应用不同的处理逻辑。
  • SimpleImputer, OrdinalEncoder, OneHotEncoder: 标准预处理组件的使用。

步骤 1:数据加载与预处理规划

任务描述

  1. 加载信贷数据集。
  2. 不进行任何手动预处理 (如手动 fillna 或 map),直接划分 X X X 和 y y y。
  3. 识别出哪些列是数值型、哪些是有序分类、哪些是无序分类,为构建管道做准备。
python 复制代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

# 1. 加载数据
data = pd.read_csv(r'F:\Training_camp\test\Credit_Data.csv')

# 2. 分离特征和标签 (直接使用原始数据)
y = data['Credit Default']
X = data.drop(['Credit Default'], axis=1)

# 3. 划分数据集 (在预处理之前划分!这是Pipeline的一大优势)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

print(f"数据划分完成!训练集: {X_train.shape}, 测试集: {X_test.shape}")

# 4. 自动识别列类型 (为 Pipeline 做准备)
# 连续数值特征
numeric_features = X.select_dtypes(exclude=['object']).columns.tolist()
# 离散分类特征 (需要进一步区分有序和无序,这里先统称为分类)
categorical_features = X.select_dtypes(include=['object']).columns.tolist()

print(f"数值特征: {len(numeric_features)} 个")
print(f"分类特征: {len(categorical_features)} 个")
复制代码
数据划分完成!训练集: (6000, 17), 测试集: (1500, 17)
数值特征: 13 个
分类特征: 4 个

步骤 2:构建处理组件 (Transformers)

核心概念

Pipeline 就像一条汽车组装线,我们需要先定义好每个环节的"机械臂":

  • 有序特征 :填充缺失值 -> OrdinalEncoder (编码为 1, 2, 3)
  • 无序特征 :填充缺失值 -> OneHotEncoder (独热编码)
  • 连续特征 :填充缺失值 -> StandardScaler (标准化)

任务

使用 Pipeline 类分别封装这三类特征的处理逻辑。

python 复制代码
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder, OrdinalEncoder
from sklearn.compose import ColumnTransformer

# --- 1. 定义 有序特征 处理流 ---
# 必须手动指定顺序,否则模型不知道大小关系
ordinal_cols = ['Home Ownership', 'Years in current job', 'Term']
ordinal_categories = [
    ['Own Home', 'Rent', 'Have Mortgage', 'Home Mortgage'], 
    ['< 1 year', '1 year', '2 years', '3 years', '4 years', '5 years', '6 years', '7 years', '8 years', '9 years', '10+ years'],
    ['Short Term', 'Long Term']
]

ordinal_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')), # 众数填补
    ('encoder', OrdinalEncoder(categories=ordinal_categories, handle_unknown='use_encoded_value', unknown_value=-1))
])

# --- 2. 定义 无序特征 处理流 ---
nominal_cols = ['Purpose']

nominal_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False)) # 独热编码
])

# --- 3. 定义 连续特征 处理流 ---
# 排除掉上面用过的列,剩下的就是连续特征
continuous_cols = [col for col in X.columns if col not in ordinal_cols + nominal_cols]

continuous_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')), # 中位数填补
    ('scaler', StandardScaler()) # 标准化 (这对逻辑回归/SVM等很重要,对树模型影响较小但无害)
])

# --- 4. 组装成一个大的处理器 (ColumnTransformer) ---
# 它的作用是:把数据按列劈开,分别扔给上面定义好的三个处理器,最后再拼起来
preprocessor = ColumnTransformer(
    transformers=[
        ('num', continuous_transformer, continuous_cols),
        ('ord', ordinal_transformer, ordinal_cols),
        ('nom', nominal_transformer, nominal_cols)
    ],
    remainder='passthrough' # 其他未指定的列保持原样
)

print("✅ 预处理组件构建完成!")
复制代码
✅ 预处理组件构建完成!

步骤 3:组装总流水线与模型训练

任务描述

preprocessor (数据处理) 和 classifier (分类模型) 串联成最终的 Pipeline 对象。

之后,我们只需要对这个 Pipeline 对象调用 .fit(),它就会自动完成所有清洗、转换和训练工作。

python 复制代码
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
import time

# 1. 组装最终管道
# 逻辑:原始数据 -> preprocessor (清洗+编码+标准) -> classifier (随机森林)
full_pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('model', RandomForestClassifier(random_state=42))
])

# 2. 训练 (Fit)
print("🚀 开始训练 Pipeline...")
start_time = time.time()

# 注意:这里直接传入原始的 X_train,管道会自动处理一切
full_pipeline.fit(X_train, y_train)

# 3. 预测 (Predict)
# 注意:直接传入原始的 X_test,管道会自动 transform 之后再预测
y_pred = full_pipeline.predict(X_test)

end_time = time.time()
print(f"✅ 训练完成!耗时: {end_time - start_time:.4f} 秒")

# 4. 评估
print("\n--- 分类报告 ---")
print(classification_report(y_test, y_pred))
复制代码
🚀 开始训练 Pipeline...
✅ 训练完成!耗时: 1.5297 秒

--- 分类报告 ---
              precision    recall  f1-score   support

           0       0.76      0.97      0.85      1059
           1       0.77      0.28      0.41       441

    accuracy                           0.76      1500
   macro avg       0.77      0.62      0.63      1500
weighted avg       0.77      0.76      0.72      1500

🎓 Day 23 总结:工程化的力量

通过今天的实战,我们将原本分散、混乱的数据处理代码,重构为了一个优雅的 Pipeline 对象。

Pipeline 的核心优势

  1. 封装性 (Encapsulation)full_pipeline.fit(X, y) 一行代码搞定所有,不用担心漏掉哪一步预处理。
  2. 安全性 (Safety) :自动在训练集上计算均值/方差,并应用到测试集,严防数据泄露
  3. 可移植性 (Portability) :这个 full_pipeline 对象可以直接保存 (Pickle),以后来了新数据,加载出来直接 .predict() 即可,无需重写清洗逻辑。

这是从"写作业"迈向"写项目"的重要一步!

相关推荐
有为少年2 小时前
数据增强在小型卷积神经网络中的有效性探究
人工智能·深度学习·神经网络·机器学习·cnn
一代明君Kevin学长2 小时前
快速自定义一个带进度监控的文件资源类
java·前端·后端·python·文件上传·文件服务·文件流
雪花desu2 小时前
什么是融入 CoT 写 prompt
人工智能·语言模型
AIBox3652 小时前
ChatGPT 中文版镜像官网,GPT5.2使用教程(2025年 12 月更新)
人工智能
HappRobot2 小时前
python类和对象
开发语言·python
测试人社区-千羽2 小时前
生物识别系统的测试安全性与漏洞防护实践
运维·人工智能·opencv·安全·数据挖掘·自动化·边缘计算
2501_924794902 小时前
企业AI转型为何难?——从“不敢用”到“用得稳”的路径重构
大数据·人工智能·重构
盼哥PyAI实验室2 小时前
Python YAML配置管理:12306项目的灵活配置方案
开发语言·python
Tezign_space2 小时前
小红书内容运营工具怎么选?专业视角拆解优质工具核心标准
大数据·人工智能·内容运营