Day 29 机器学习管道 pipeline

@浙大疏锦行

pipeline在机器学习领域可以翻译为"管道",也可以翻译为"流水线",是机器学习中一个重要的概念。在机器学习中,通常会按照一定的顺序对数据进行预处理、特征提取、模型训练和模型评估等步骤,以实现机器学习模型的训练和评估。为了方便管理这些步骤,我们可以使用pipeline来构建一个完整的机器学习流水线。pipeline是一个用于组合多个估计器(estimator)的 estimator,它实现了一个流水线,其中每个估计器都按照一定的顺序执行。在pipeline中,每个估计器都实现了fit和transform方法,fit方法用于训练模型,transform方法用于对数据进行预处理和特征提取。

转换器(transformer)是一个用于对数据进行预处理和特征提取的 estimator,它实现一个 transform 方法,用于对数据进行预处理和特征提取。转换器通常用于对数据进行预处理,例如对数据进行归一化、标准化、缺失值填充等。转换器也可以用于对数据进行特征提取,例如对数据进行特征选择、特征组合等。转换器的特点是无状态的,即它们不会存储任何关于数据的状态信息(指的是不存储内参)。转换器仅根据输入数据学习转换规则(比如函数规律、外参),并将其应用于新的数据。因此,转换器可以在训练集上学习转换规则,并在训练集之外的新数据上应用这些规则。

常见的转换器包括数据缩放器(如StandardScaler、MinMaxScaler)、特征选择器(如SelectKBest、PCA)、特征提取器(如CountVectorizer、TF-IDFVectorizer)等。

估计器(Estimator)是实现机器学习算法的对象或类。它用于拟合(fit)数据并进行预测(predict)。估计器是机器学习模型的基本组成部分,用于从数据中学习模式、进行预测和进行模型评估。估计器的主要方法是fit和predict。fit方法用于根据输入数据学习模型的参数和规律,而predict方法用于对新的未标记样本进行预测。估计器的特点是有状态的,即它们在训练过程中存储了关于数据的状态信息,以便在预测阶段使用。估计器通过学习训练数据中的模式和规律来进行预测。因此,估计器需要在训练集上进行训练,并使用训练得到的模型参数对新数据进行预测。

常见的估计器包括分类器(classifier)、回归器(regresser)、聚类器(clusterer)。

机器学习的管道(Pipeline)机制通过将多个转换器和估计器按顺序连接在一起,可以构建一个完整的数据处理和模型训练流程。在管道机制中,可以使用Pipeline类来组织和连接不同的转换器和估计器。Pipeline类提供了一种简单的方式来定义和管理机器学习任务的流程。

管道机制是按照封装顺序依次执行的一种机制,在机器学习算法中得以应用的根源在于,参数集在新数据集(比如测试集)上的重复使用。且代码看上去更加简洁明确。这也意味着,很多个不同的数据集,只要处理成管道的输入形式,后续的代码就可以复用。(这里为我们未来的python文件拆分做铺垫),也就是把很多个类和函数操作写进一个新的pipeline中。

这符合编程中的一个非常经典的思想:don't repeat yourself。(dry原则),也叫做封装思想,我们之前提到过类似的思想的应用: 函数、类,现在我们来说管道。

Pipeline最大的价值和核心应用场景之一,就是与交叉验证和网格搜索等结合使用,来:

  1. 防止数据泄露: 这是在使用交叉验证时,Pipeline自动完成预处理并在每个折叠内独立fit/transform的关键优势。

  2. 简化超参数调优: 可以方便地同时调优预处理步骤和模型的参数。

管道意味着你可以把整个流程串起来,把所有参数写在外面,即使有的过程实际中不需要,传入的参数为0,那么这个参数就会被忽略。保证流程可以向下兼容。--所以说管道工程最大的优势,是把操作和参数分割开来,只要熟悉整个流程,不需要阅读完整的代码去找对应操作的部分了,只需要在参数列表中设置好参数,就可以完成整个流程。-----这个思想很符合我们后续面对的复杂项目需要拆分python文件的场景,所以我们的内容真的是花心思编排,不断为后续做铺垫。

python 复制代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import time
import warnings
warnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# ====================== 扩展导入:兼容分类/回归任务 ======================
# Pipeline核心工具
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OrdinalEncoder, OneHotEncoder, StandardScaler, MinMaxScaler
from sklearn.impute import SimpleImputer

# 模型:分类+回归(可替换为任意sklearn兼容模型)
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor

# 评估指标:分类+回归全覆盖
from sklearn.metrics import (
    classification_report, confusion_matrix, accuracy_score, precision_score, recall_score, f1_score,
    mean_absolute_error, mean_squared_error, r2_score
)
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris, fetch_california_housing  # 示例数据集


# ====================== 通用Pipeline构建函数 ======================
def build_universal_pipeline(
    task_type: str,  # 'classification' 或 'regression'
    ordinal_features: list,
    ordinal_categories: list,
    nominal_features: list,
    continuous_features: list,
    model,  # 传入任意sklearn模型(分类/回归)
    ordinal_impute_strategy: str = 'most_frequent',
    nominal_impute_strategy: str = 'most_frequent',
    continuous_impute_strategy: str = 'most_frequent',
    scaler_type: str = 'standard'  # 'standard' 或 'minmax'
):
    """
    构建通用机器学习Pipeline
    :param task_type: 任务类型 'classification'/'regression'
    :param ordinal_features: 有序分类特征列表
    :param ordinal_categories: 有序特征的类别顺序(与ordinal_features一一对应)
    :param nominal_features: 无序分类特征列表
    :param continuous_features: 连续特征列表
    :param model: 机器学习模型(如RandomForestClassifier/RandomForestRegressor)
    :param ordinal_impute_strategy: 有序特征缺失值填充策略
    :param nominal_impute_strategy: 无序特征缺失值填充策略
    :param continuous_impute_strategy: 连续特征缺失值填充策略
    :param scaler_type: 连续特征缩放方式
    :return: 完整Pipeline
    """
    # 1. 有序分类特征预处理
    ordinal_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy=ordinal_impute_strategy)),
        ('encoder', OrdinalEncoder(
            categories=ordinal_categories,
            handle_unknown='use_encoded_value',
            unknown_value=-1
        ))
    ])

    # 2. 无序分类特征预处理
    nominal_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy=nominal_impute_strategy)),
        ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
    ])

    # 3. 连续特征预处理(支持两种缩放方式)
    scaler = StandardScaler() if scaler_type == 'standard' else MinMaxScaler()
    continuous_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy=continuous_impute_strategy)),
        ('scaler', scaler)
    ])

    # 4. 整合所有预处理
    transformers = []
    if ordinal_features:
        transformers.append(('ordinal', ordinal_transformer, ordinal_features))
    if nominal_features:
        transformers.append(('nominal', nominal_transformer, nominal_features))
    if continuous_features:
        transformers.append(('continuous', continuous_transformer, continuous_features))

    preprocessor = ColumnTransformer(
        transformers=transformers,
        remainder='passthrough'  # 保留未指定的列(如有)
    )

    # 5. 构建完整Pipeline(预处理 + 模型)
    pipeline = Pipeline(steps=[
        ('preprocessor', preprocessor),
        ('model', model)
    ])

    return pipeline


# ====================== 通用评估函数 ======================
def evaluate_model(
    task_type: str,
    y_true: np.ndarray,
    y_pred: np.ndarray,
    y_pred_proba: np.ndarray = None  # 分类任务可选概率输出
):
    """
    通用模型评估(自动适配分类/回归)
    :param task_type: 任务类型
    :param y_true: 真实标签
    :param y_pred: 预测标签
    :param y_pred_proba: 分类任务预测概率(可选)
    """
    if task_type == 'classification':
        print("\n【分类任务评估指标】")
        print(f"准确率(Accuracy): {accuracy_score(y_true, y_pred):.4f}")
        print(f"精确率(Precision): {precision_score(y_true, y_pred, average='weighted', zero_division=0):.4f}")
        print(f"召回率(Recall): {recall_score(y_true, y_pred, average='weighted', zero_division=0):.4f}")
        print(f"F1分数: {f1_score(y_true, y_pred, average='weighted', zero_division=0):.4f}")
        print("\n分类报告:")
        print(classification_report(y_true, y_pred))
        print("混淆矩阵:")
        print(confusion_matrix(y_true, y_pred))
    
    elif task_type == 'regression':
        print("\n【回归任务评估指标】")
        mae = mean_absolute_error(y_true, y_pred)
        mse = mean_squared_error(y_true, y_pred)
        rmse = np.sqrt(mse)
        r2 = r2_score(y_true, y_pred)
        print(f"平均绝对误差(MAE): {mae:.4f}")
        print(f"均方误差(MSE): {mse:.4f}")
        print(f"均方根误差(RMSE): {rmse:.4f}")
        print(f"决定系数(R²): {r2:.4f}")


# ====================== 示例1:分类任务(鸢尾花数据集) ======================
print("="*60 + " 分类任务示例 " + "="*60)
# 1. 加载示例数据(替换为你的data.csv即可)
iris = load_iris()
X_iris = pd.DataFrame(iris.data, columns=['花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'])
y_iris = pd.Series(iris.target, name='花种类')

# 2. 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X_iris, y_iris, test_size=0.2, random_state=42
)

# 3. 定义特征配置(鸢尾花无分类特征,演示空值处理)
ordinal_features_iris = []
ordinal_categories_iris = []
nominal_features_iris = []
continuous_features_iris = X_iris.columns.tolist()  # 全部为连续特征

# 4. 构建Pipeline(分类模型)
clf_model = RandomForestClassifier(random_state=42, n_estimators=100)
clf_pipeline = build_universal_pipeline(
    task_type='classification',
    ordinal_features=ordinal_features_iris,
    ordinal_categories=ordinal_categories_iris,
    nominal_features=nominal_features_iris,
    continuous_features=continuous_features_iris,
    model=clf_model,
    continuous_impute_strategy='median'  # 连续特征用中位数填充
)

# 5. 训练+预测
start_time = time.time()
clf_pipeline.fit(X_train, y_train)
y_pred_clf = clf_pipeline.predict(X_test)
y_pred_proba_clf = clf_pipeline.predict_proba(X_test)  # 分类任务特有
end_time = time.time()

# 6. 输出结果
print(f"分类任务训练+预测耗时: {end_time - start_time:.4f} 秒")
evaluate_model(
    task_type='classification',
    y_true=y_test,
    y_pred=y_pred_clf,
    y_pred_proba=y_pred_proba_clf
)


# ====================== 示例2:回归任务(加州房价数据集) ======================
print("\n" + "="*60 + " 回归任务示例 " + "="*60)
# 1. 加载示例数据
california = fetch_california_housing()
X_cali = pd.DataFrame(california.data, columns=california.feature_names)
y_cali = pd.Series(california.target, name='房价')

# 2. 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X_cali, y_cali, test_size=0.2, random_state=42
)

# 3. 定义特征配置(加州房价无分类特征)
ordinal_features_cali = []
ordinal_categories_cali = []
nominal_features_cali = []
continuous_features_cali = X_cali.columns.tolist()

# 4. 构建Pipeline(回归模型)
reg_model = RandomForestRegressor(random_state=42, n_estimators=100)
reg_pipeline = build_universal_pipeline(
    task_type='regression',
    ordinal_features=ordinal_features_cali,
    ordinal_categories=ordinal_categories_cali,
    nominal_features=nominal_features_cali,
    continuous_features=continuous_features_cali,
    model=reg_model,
    scaler_type='minmax'  # 改用MinMax缩放
)

# 5. 训练+预测
start_time = time.time()
reg_pipeline.fit(X_train, y_train)
y_pred_reg = reg_pipeline.predict(X_test)
end_time = time.time()

# 6. 输出结果
print(f"回归任务训练+预测耗时: {end_time - start_time:.4f} 秒")
evaluate_model(
    task_type='regression',
    y_true=y_test,
    y_pred=y_pred_reg
)


# ====================== 适配你的原始数据(Credit Default) ======================
print("\n" + "="*60 + " 适配你的信贷违约数据 " + "="*60)
# 1. 加载你的数据
# data = pd.read_csv('data.csv')  # 取消注释使用你的数据
# y = data['Credit Default']
# X = data.drop(['Credit Default'], axis=1)

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

# 3. 特征配置(和你原代码一致)
ordinal_features_credit = ['Home Ownership', 'Years in current job', 'Term']
ordinal_categories_credit = [
    ['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']
]
nominal_features_credit = ['Purpose']
object_cols_credit = X.select_dtypes(include=['object']).columns.tolist()  # 自动识别分类列
continuous_features_credit = X.columns.difference(object_cols_credit).tolist()  # 自动识别连续列

# 4. 构建Pipeline(可替换为任意分类模型)
credit_model = RandomForestClassifier(random_state=42)
credit_pipeline = build_universal_pipeline(
    task_type='classification',
    ordinal_features=ordinal_features_credit,
    ordinal_categories=ordinal_categories_credit,
    nominal_features=nominal_features_credit,
    continuous_features=continuous_features_credit,
    model=credit_model
)

# 5. 训练+评估
# start_time = time.time()
# credit_pipeline.fit(X_train, y_train)
# y_pred_credit = credit_pipeline.predict(X_test)
# end_time = time.time()

# print(f"信贷违约预测耗时: {end_time - start_time:.4f} 秒")
# evaluate_model(task_type='classification', y_true=y_test, y_pred=y_pred_credit)
相关推荐
努力也学不会java40 分钟前
【docker】Docker Image(镜像)
java·运维·人工智能·机器学习·docker·容器
zhangfeng113340 分钟前
suppr.wilddata.cn 文献检索,用中文搜 PubMed 一种基于大语言模型的智能搜索引擎构建方法
人工智能·搜索引擎·语言模型
大千AI助手41 分钟前
高维空间中的高效导航者:球树(Ball Tree)算法深度解析
人工智能·算法·机器学习·数据挖掘·大千ai助手·球树·ball-tree
新知图书41 分钟前
使用FastGPT知识库构建智能客服的示例
人工智能·ai agent·智能体·大模型应用开发·大模型应用
生信大表哥44 分钟前
GPT-5-Codex VS Gemini 3 VS Claude Sonnet 4.5 新手小白入门学习教程
人工智能·gpt·学习·rstudio·数信院生信服务器
子午1 小时前
【植物识别系统】Python+TensorFlow+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习
ONLYOFFICE1 小时前
ONLYOFFICE 文档与桌面编辑器 9.2 版本更新说明
人工智能·编辑器·onlyoffice
sensen_kiss1 小时前
INT301 Bio-computation 生物计算(神经网络)Pt.10 联想存储器与HOPFIELD网络
人工智能·深度学习·神经网络
九千七5261 小时前
sklearn学习(6)决策树
人工智能·python·学习·决策树·机器学习·sklearn