
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最大的价值和核心应用场景之一,就是与交叉验证和网格搜索等结合使用,来:
-
防止数据泄露: 这是在使用交叉验证时,Pipeline自动完成预处理并在每个折叠内独立fit/transform的关键优势。
-
简化超参数调优: 可以方便地同时调优预处理步骤和模型的参数。
管道意味着你可以把整个流程串起来,把所有参数写在外面,即使有的过程实际中不需要,传入的参数为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)