【机器学习】管道化与自动化建模

机器学习

Scikit-learn

管道化与自动化建模

Pipeline 基础

为什么要用管道化?

先思考一个 "非管道化" 的痛点,假设我们要训练一个模型,流程通常是:

  1. 数据预处理(如标准化);
  2. 特征工程(如降维);
  3. 模型训练;
  4. 用测试集评估。

如果不用管道,代码可能是这样的:

python 复制代码
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

# 1. 加载数据并划分
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

# 2. 预处理:标准化(只对训练集拟合)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # 训练集:fit+transform
X_test_scaled = scaler.transform(X_test)        # 测试集:只transform(避免信息泄露)

# 3. 特征工程:PCA降维
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_scaled)  # 训练集:fit+transform
X_test_pca = pca.transform(X_test_scaled)        # 测试集:只transform

# 4. 模型训练
model = LogisticRegression()
model.fit(X_train_pca, y_train)

# 5. 评估
print("测试集准确率:", model.score(X_test_pca, y_test))

这段代码看起来没问题,但实际使用中会暴露 3 个严重问题:

  1. 步骤割裂,容易出错:预测新数据时,必须严格重复 "标准化→PCA→预测" 的步骤,少一步或顺序错了都会导致结果错误(比如忘记 PCA 就直接预测);
  2. 无法与交叉验证兼容 :如果用GridSearchCV调参,需要手动在每折训练集上做 "标准化→PCA",否则会导致 "验证集信息泄露"(用了全量数据的统计信息);
  3. 代码冗余,难以维护:当步骤增多(如加缺失值处理、特征选择),代码会变得冗长,复用性差。

Pipeline 的核心解决方案:"封装流程,自动衔接"

Pipeline(管道)的本质是将多个建模步骤(如预处理、特征工程、模型)"串联" 成一个整体对象 ,这个对象能像单个模型一样调用fit/predict,且内部会自动处理步骤间的衔接,避免上述问题。

  1. Pipeline 的基本结构

    Pipeline重构上面的流程,代码如下:

    python 复制代码
    from sklearn.pipeline import Pipeline
    
    # 定义管道:按顺序串联3个步骤
    pipe = Pipeline([
        ('scaler', StandardScaler()),  # 步骤1:标准化(命名为scaler)
        ('pca', PCA(n_components=2)),  # 步骤2:PCA降维(命名为pca)
        ('model', LogisticRegression())# 步骤3:逻辑回归模型(命名为model)
    ])
    • 管道由有序的步骤列表 组成,每个步骤是一个元组(步骤名, 转换器/估计器)
    • 转换器(Transformer) :有fittransform方法的对象(如StandardScalerPCA),用于数据处理;
    • 估计器(Estimator) :有fit方法的对象(如LogisticRegression),通常是管道的最后一步(模型)。
  2. 管道的 "一键训练与预测"

    管道定义后,训练和预测变得极其简单:

    python 复制代码
    # 1. 训练管道(自动完成:训练集标准化→PCA→模型训练)
    pipe.fit(X_train, y_train)  # 只需传入原始训练数据,内部自动处理所有步骤
    
    # 2. 预测(自动完成:测试集标准化→PCA→模型预测)
    y_pred = pipe.predict(X_test)  # 传入原始测试数据,内部按训练时的步骤处理
    
    # 3. 评估
    print("测试集准确率:", pipe.score(X_test, y_test))  # 直接用管道评估

管道内部的神奇之处:

  • 调用fit(X_train, y_train)时,管道会按顺序对每个步骤执行fit_transform(最后一步模型执行fit):
    1. scaler.fit_transform(X_train) → 得到标准化后的训练数据;
    2. pca.fit_transform(标准化数据) → 得到降维后的训练数据;
    3. model.fit(降维数据, y_train) → 训练模型。
  • 调用predict(X_test)时,管道会对每个步骤执行transform(用训练时拟合的参数):
    1. scaler.transform(X_test) → 用训练集的均值 / 标准差标准化测试数据;
    2. pca.transform(标准化测试数据) → 用训练集的 PCA 参数降维;
    3. model.predict(降维测试数据) → 预测。

Pipeline 解决的 3 大核心问题

  1. 避免步骤遗漏或顺序错误:预测时无需手动重复预处理步骤,管道会自动按训练时的顺序执行,杜绝 "忘记标准化""PCA 顺序错了" 等低级错误。
  2. 防止信息泄露(Data Leakage) :管道与交叉验证(如GridSearchCV)结合时,会在每折训练集上单独执行fit_transform ,测试集只执行transform,确保测试集的信息不会影响训练过程(这是最关键的优势!)。
  3. 简化代码,便于复用:将复杂流程封装成一个对象,调参、保存、部署都只需操作管道,代码更简洁,且可直接复用在新数据上。

Pipeline 注意事项

  1. 步骤名的命名规则

    • 步骤名可自定义(如scalerpca),但不能包含空格或特殊字符;
    • 后续调参时需要用 "步骤名__参数名" 的格式(如scaler__with_mean),所以命名要简洁易懂。
  2. 最后一步必须是估计器

    • 管道的最后一个步骤必须是有fit方法的估计器(如模型),前面的步骤必须是有fit_transform的转换器;
    • 错误示例:最后一步放PCA(转换器),管道无法调用predict(因为PCA没有predict方法)。
  3. 查看管道内部步骤

    named_steps属性可访问管道中的某个步骤,方便查看中间结果或参数:

    python 复制代码
    # 查看PCA步骤的解释方差比
    print("PCA解释方差比:", pipe.named_steps['pca'].explained_variance_ratio_)
    # 查看模型的系数
    print("逻辑回归系数:", pipe.named_steps['model'].coef_)

ColumnTransformer

为什么需要 ColumnTransformer?

现实中的数据集很少只有单一类型特征,比如一份用户数据可能包含:

  • 数值特征(年龄、收入)→ 需要标准化 / 归一化;
  • 类别特征(性别、城市)→ 需要独热编码 / 标签编码;
  • 文本特征(用户评论)→ 需要 TF-IDF 转换。

如果用普通 Pipeline,所有特征会被同一套预处理流程处理(比如对类别特征做标准化,这显然不合理)。ColumnTransformer 的作用是:按特征类型拆分数据,对不同子集应用不同的预处理,最后再合并结果

ColumnTransformer 基础用法:分而治之

以 "混合类型特征数据集" 为例,演示流程:

  1. 准备数据(含数值和类别特征)

    python 复制代码
    import pandas as pd
    
    # 模拟用户数据:包含2个数值特征,1个类别特征,1个目标标签
    data = pd.DataFrame({
        'age': [25, 32, 47, 51, 62, 36],  # 数值特征
        'income': [40000, 54000, 82000, 90000, 120000, 65000],  # 数值特征
        'city': ['Beijing', 'Shanghai', 'Beijing', 'Guangzhou', 'Shanghai', 'Shenzhen'],  # 类别特征
        'is_purchase': [0, 1, 1, 0, 1, 0]  # 目标标签(是否购买)
    })
    
    X = data[['age', 'income', 'city']]  # 特征(包含数值和类别)
    y = data['is_purchase']  # 标签
  2. 定义 "特征分组" 和 "对应预处理"

    首先明确哪些特征是同一类型,需要哪些预处理:

    • 数值特征(ageincome)→ 用 StandardScaler 标准化;
    • 类别特征(city)→ 用 OneHotEncoder 独热编码(生成如 city_Beijing 等哑变量)。

    然后用 ColumnTransformer 整合这两个预处理方案:

    python 复制代码
    from sklearn.compose import ColumnTransformer
    from sklearn.preprocessing import StandardScaler, OneHotEncoder
    
    # 1. 定义特征分组(指定哪些列属于哪类)
    num_features = ['age', 'income']  # 数值特征列名
    cat_features = ['city']           # 类别特征列名
    
    # 2. 定义 ColumnTransformer:对不同特征组应用不同预处理
    preprocessor = ColumnTransformer(
        transformers=[
            ('num', StandardScaler(), num_features),  # 名称:num;处理器:StandardScaler;作用列:num_features
            ('cat', OneHotEncoder(), cat_features)    # 名称:cat;处理器:OneHotEncoder;作用列:cat_features
        ])
    • transformers 参数是一个列表,每个元素是三元组 (名称, 处理器, 特征列)
      • 名称:自定义(后续调参用);
      • 处理器:对该组特征的预处理工具(如 StandardScaler);
      • 特征列:指定哪些列属于该组(可用列名或索引,推荐列名更清晰)。
  3. 整合到 Pipeline:预处理 + 模型

    ColumnTransformer 本身是一个 "特征预处理管道",需要和模型一起整合到 Pipeline 中,形成完整流程:

    python 复制代码
    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import LogisticRegression
    from sklearn.model_selection import train_test_split
    
    # 1. 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
    
    # 2. 定义完整管道:预处理(ColumnTransformer)→ 模型
    full_pipe = Pipeline([
        ('preprocessor', preprocessor),  # 第一步:用ColumnTransformer处理特征
        ('classifier', LogisticRegression())  # 第二步:模型训练
    ])
    
    # 3. 训练管道(自动处理不同特征)
    full_pipe.fit(X_train, y_train)
    
    # 4. 评估
    print("测试集准确率:", round(full_pipe.score(X_test, y_test), 4))
  4. 查看预处理结果(理解内部逻辑)

    通过 fit_transform 可查看预处理后的特征矩阵,理解 ColumnTransformer 如何工作:

    python 复制代码
    # 对训练集应用预处理,查看结果
    X_train_processed = preprocessor.fit_transform(X_train)
    
    # 打印处理后的特征矩阵(稀疏矩阵转为数组,方便查看)
    print("预处理后的训练集特征矩阵:")
    print(X_train_processed.toarray() if hasattr(X_train_processed, 'toarray') else X_train_processed)
    
    # 查看特征名称(OneHotEncoder生成的哑变量名)
    cat_encoder = preprocessor.named_transformers_['cat']  # 获取类别处理器
    cat_feature_names = cat_encoder.get_feature_names_out(cat_features)  # 哑变量列名
    all_feature_names = list(num_features) + list(cat_feature_names)  # 合并所有特征名
    print("\n预处理后的特征名称:", all_feature_names)

    输出结果:

    mathematica 复制代码
    测试集准确率: 0.5
    预处理后的训练集特征矩阵:
    [[-1.39776866 -1.21755191  0.          0.          0.          1.        ]
     [-0.21504133 -0.36401036  1.          0.          0.          0.        ]
     [ 1.39776866  1.54390603  0.          0.          1.          0.        ]
     [ 0.21504133  0.03765624  0.          1.          0.          0.        ]]
    
    预处理后的特征名称: ['age', 'income', 'city_Beijing', 'city_Guangzhou', 'city_Shanghai', 'city_Shenzhen']
    • 数值特征 ageincome 被标准化(均值为 0,标准差为 1);
    • 类别特征 city 被转为哑变量(如 city_Beijing 为 1 表示该样本来自北京);
    • 最终特征矩阵是两部分的拼接(数值特征在前,哑变量在后)。

ColumnTransformer 的关键参数

  1. remainder:未指定的特征如何处理?

    默认情况下,ColumnTransformer 只会处理 transformers 中指定的特征,未指定的特征会被丢弃。若想保留未指定的特征(如无需预处理的特征),可设置 remainder='passthrough'

    python 复制代码
    # 假设数据新增一列无需处理的特征"user_id"(直接保留)
    data['user_id'] = [1001, 1002, 1003, 1004, 1005, 1006]
    X = data[['age', 'income', 'city', 'user_id']]
    
    # 定义ColumnTransformer,保留未指定的特征(user_id)
    preprocessor_with_remainder = ColumnTransformer(
        transformers=[
            ('num', StandardScaler(), ['age', 'income']),
            ('cat', OneHotEncoder(), ['city'])
        ],
        remainder='passthrough'  # 未指定的特征直接保留
    )
    
    # 查看结果(最后一列是未处理的user_id)
    X_processed = preprocessor_with_remainder.fit_transform(X)
    print("保留未处理特征的结果:\n", X_processed)
  2. 对不同特征组用 "子管道"

    如果某类特征需要多步预处理(如 "缺失值填充→标准化"),可在 ColumnTransformer 中嵌套 Pipeline 作为处理器:

    python 复制代码
    from sklearn.impute import SimpleImputer  # 缺失值填充
    
    # 数值特征的预处理子管道:先填充缺失值,再标准化
    num_pipe = Pipeline([
        ('imputer', SimpleImputer(strategy='median')),  # 用中位数填充缺失值
        ('scaler', StandardScaler())  # 标准化
    ])
    
    # 类别特征的预处理子管道:先填充缺失值,再独热编码
    cat_pipe = Pipeline([
        ('imputer', SimpleImputer(strategy='most_frequent')),  # 用众数填充缺失值
        ('encoder', OneHotEncoder())  # 独热编码
    ])
    
    # 用子管道构建ColumnTransformer
    preprocessor_with_pipes = ColumnTransformer([
        ('num', num_pipe, num_features),
        ('cat', cat_pipe, cat_features)
    ])

    这种 "子管道嵌套" 的方式,能处理更复杂的预处理逻辑(如多步缺失值处理、特征转换)。

ColumnTransformer + GridSearchCV:跨特征组调参

ColumnTransformer 中的任何处理器参数,都能通过 GridSearchCV 调优,参数名格式为:

复制代码
预处理步骤名__子处理器名__参数名

例如,调优数值特征的标准化方式和模型的正则化系数:

python 复制代码
from sklearn.model_selection import GridSearchCV

# 定义参数网格(注意参数名格式)
param_grid = {
    # 调优数值预处理管道中的标准化是否减去均值(步骤名preprocessor→子步骤num→参数with_mean)
    'preprocessor__num__with_mean': [True, False],
    # 调优模型的正则化系数C(步骤名classifier→参数C)
    'classifier__C': [0.1, 1, 10]
}

# 网格搜索
grid = GridSearchCV(full_pipe, param_grid, cv=3, scoring='accuracy')
grid.fit(X_train, y_train)

print("最佳参数:", grid.best_params_)
print("最佳交叉验证准确率:", grid.best_score_.round(4))

FeatureUnion

在实际特征工程中,单一的特征处理方式(如仅用 PCA 降维)往往不够,我们可能需要同时使用多种方法(如 PCA 降维和统计特征选择),再将结果合并。FeatureUnion 就是实现这一需求的工具,它能让不同的特征提取管道 "并行工作",最后汇总成果。

为什么需要 FeatureUnion?

特征工程的核心是 "尽可能保留数据中的有效信息",但不同的特征提取方法擅长捕捉不同类型的信息:

  • PCA:擅长提取数据中的线性主成分,压缩维度的同时保留最大方差;
  • SelectKBest:擅长根据统计量(如卡方值)筛选与标签相关性高的特征;
  • 自定义特征:比如手动构造的多项式特征、交互特征等。

如果只用其中一种方法,可能会丢失其他方法能捕捉的信息。FeatureUnion 的作用是:让多个特征提取管道并行处理同一批数据,然后将各自的结果横向拼接(按列合并),形成更全面的特征矩阵

FeatureUnion 基础用法:并行提取,合并特征

以 "鸢尾花数据集" 为例,同时用 PCA 和 SelectKBest 提取特征,再合并后输入模型:

  1. 准备数据与定义特征提取管道

    python 复制代码
    from sklearn.datasets import load_iris
    from sklearn.decomposition import PCA
    from sklearn.feature_selection import SelectKBest, f_classif
    from sklearn.pipeline import FeatureUnion, Pipeline
    from sklearn.linear_model import LogisticRegression
    from sklearn.model_selection import train_test_split
    
    # 加载数据
    X, y = load_iris(return_X_y=True)
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
    
    # 定义两个并行的特征提取管道
    # 管道1:PCA降维(保留2个主成分)
    pca_pipe = Pipeline([
        ('pca', PCA(n_components=2))
    ])
    
    # 管道2:SelectKBest(筛选2个与标签最相关的特征)
    select_k_best_pipe = Pipeline([
        ('select', SelectKBest(score_func=f_classif, k=2))  # 用f_classif计算ANOVA得分
    ])
  2. 用 FeatureUnion 合并特征提取结果

    python 复制代码
    # 合并两个特征提取管道:同时执行PCA和SelectKBest,结果按列拼接
    feature_union = FeatureUnion([
        ('pca_features', pca_pipe),  # 名称:pca_features;对应管道:pca_pipe
        ('selected_features', select_k_best_pipe)  # 名称:selected_features;对应管道:select_k_best_pipe
    ])
    • FeatureUnion 的参数是一个列表,每个元素是元组 (名称, 转换器/管道),格式与 Pipeline 类似;
    • 每个转换器 / 管道会独立处理输入数据(如 pca_pipe 处理原始特征得到 PCA 结果,select_k_best_pipe 处理原始特征得到筛选后的特征);
    • 最终输出是两个结果的横向拼接(例如:原始特征 4 维 → PCA 得到 2 维 + 筛选得到 2 维 → 合并后 4 维特征矩阵)。
  3. 整合到完整管道:特征合并 + 模型训练

    python 复制代码
    # 完整管道:特征合并(FeatureUnion)→ 模型(逻辑回归)
    full_pipe = Pipeline([
        ('feature_engineering', feature_union),  # 第一步:合并特征
        ('classifier', LogisticRegression(max_iter=200))  # 第二步:模型训练
    ])
    
    # 训练与评估
    full_pipe.fit(X_train, y_train)
    print("测试集准确率:", full_pipe.score(X_test, y_test).round(4))  # 输出:1.0(性能优异)
  4. 查看合并后的特征(理解内部逻辑)

    通过 fit_transform 查看特征合并的具体结果:

    python 复制代码
    # 对训练集应用特征合并
    X_train_combined = feature_union.fit_transform(X_train, y_train)  # 注意:部分特征提取需要标签(如SelectKBest)
    
    print("原始训练集形状:", X_train.shape)  # (112, 4) → 112样本,4特征
    print("合并后训练集形状:", X_train_combined.shape)  # (112, 4) → 2(PCA)+ 2(筛选)=4特征
    
    # 查看前5个样本的合并特征
    print("\n前5个样本的合并特征:")
    print(X_train_combined[:5, :])  # 前2列是PCA结果,后2列是SelectKBest筛选的特征

    输出结果:

    mathematica 复制代码
    测试集准确率: 1.0
    原始训练集形状: (112, 4)
    合并后训练集形状: (112, 4)
    
    前5个样本的合并特征:
    [[-2.77109765  0.36609042  1.4         0.2       ]
     [-2.68813825  0.85121143  1.5         0.1       ]
     [ 1.37004014 -0.55462789  5.1         1.9       ]
     [ 0.76518066  0.21536736  4.5         1.6       ]
     [ 1.17701069  0.43853186  4.7         1.5       ]]
    • 合并后的特征矩阵保留了两种方法的结果:PCA 捕捉的全局方差信息 + SelectKBest 捕捉的与标签相关的局部信息;
    • 这种 "多源特征融合" 往往比单一方法更有效(尤其在复杂数据上)。

FeatureUnion 注意事项

  1. 与 ColumnTransformer 结合:先分类型,再并行提取

    实际场景中,常需要先按特征类型拆分(用 ColumnTransformer),再对某类特征用多种方法并行提取(用 FeatureUnion)。例如:

    • 数值特征:同时做 PCA 和标准化 + 多项式特征;
    • 类别特征:独热编码。

    示例代码:

    python 复制代码
    from sklearn.preprocessing import PolynomialFeatures, StandardScaler
    from sklearn.compose import ColumnTransformer
    
    # 假设数据有数值特征和类别特征(此处用鸢尾花数值特征模拟)
    num_features = [0, 1, 2, 3]  # 鸢尾花的4个数值特征(用索引)
    
    # 数值特征的并行提取管道:PCA + 标准化+多项式特征
    num_feature_union = FeatureUnion([
        ('pca', PCA(n_components=2)),
        ('poly', Pipeline([
            ('scaler', StandardScaler()),
            ('poly', PolynomialFeatures(degree=2))  # 生成二次多项式特征
        ]))
    ])
    
    # 用ColumnTransformer整合(此处只有数值特征,可扩展到多类型)
    preprocessor = ColumnTransformer([
        ('num', num_feature_union, num_features)
    ])
    
    # 完整管道
    pipe = Pipeline([
        ('preprocessor', preprocessor),
        ('classifier', LogisticRegression(max_iter=200))
    ])
    
    pipe.fit(X_train, y_train)
    print("结合ColumnTransformer的准确率:", round(pipe.score(X_test, y_test),4))
  2. 调优 FeatureUnion 中的参数

    FeatureUnion 中的每个子管道参数,也可通过 GridSearchCV 调优,参数名格式为:

    复制代码
    FeatureUnion步骤名__子管道名__子参数名

    例如,调优 PCA 的主成分数量和 SelectKBest 的 k 值:

    python 复制代码
    from sklearn.model_selection import GridSearchCV
    
    param_grid = {
        # 调优PCA的n_components(feature_engineering是FeatureUnion的步骤名)
        'feature_engineering__pca_features__pca__n_components': [1, 2, 3],
        # 调优SelectKBest的k值
        'feature_engineering__selected_features__select__k': [1, 2, 3]
    }
    
    grid = GridSearchCV(full_pipe, param_grid, cv=3, scoring='accuracy')
    grid.fit(X_train, y_train)
    
    print("最佳参数:", grid.best_params_)
    print("最佳准确率:", grid.best_score_.round(4))
  3. 特征维度膨胀问题

    FeatureUnion 会合并多个特征提取结果,可能导致特征维度急剧增加(如两种方法各生成 100 维特征,合并后 200 维),带来两个问题:

    • 计算成本上升;
    • 维度灾难(过拟合风险增加)。

    解决办法

    • 控制每个子管道的输出维度(如 PCA 少保留主成分,SelectKBest 少选特征);
    • 合并后增加特征选择步骤(如在模型前加 SelectFromModel)。

Pipeline + GridSearchCV

为什么需要 "管道 + 网格搜索" 的组合?

单独使用 GridSearchCV 时,若数据需要预处理(如标准化、编码),很容易出现 "信息泄露"(用全量数据的统计信息预处理验证集)。而 Pipeline 能保证 "预处理 + 模型" 的步骤在每折交叉验证中独立执行,再结合 GridSearchCV 对整个管道的参数调优,就能实现:

  • 全程无信息泄露:每折训练集单独预处理,验证集严格 "unseen";
  • 参数调优全覆盖:不仅能调模型参数,还能调预处理、特征工程的参数(如 PCA 主成分数、标准化方式);
  • 代码简洁可复用:一行代码启动 "预处理→特征工程→模型训练→参数优化" 全流程。

自动化调参流程(以房价预测为例)

用加州房价数据集(回归任务),构建一个包含 "预处理→特征工程→模型" 的管道,并对全流程参数调优:

  1. 数据与管道设计

    加州房价数据包含 8 个数值特征(如平均收入、房龄),目标是预测房价中位数(连续值)。设计的管道流程:

    1. 预处理:数值特征标准化(StandardScaler);
    2. 特征工程:可选 PCA 降维(探索是否需要降维);
    3. 模型:随机森林回归(调优树的数量和深度)。
  2. 管道定义 + 网格搜索

    python 复制代码
    from sklearn.datasets import fetch_california_housing
    from sklearn.model_selection import train_test_split, GridSearchCV
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import StandardScaler
    from sklearn.decomposition import PCA
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.metrics import r2_score
    
    # 1. 加载数据并划分
    data = fetch_california_housing()
    X, y = data.data, data.target
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    
    # 2. 定义完整管道:标准化 → 可选PCA → 随机森林
    pipe = Pipeline([
        ('scaler', StandardScaler()),  # 步骤1:标准化
        ('pca', PCA()),                # 步骤2:PCA(默认保留所有特征,后续调参控制n_components)
        ('rf', RandomForestRegressor(random_state=42))  # 步骤3:随机森林
    ])
    
    # 3. 定义参数网格(覆盖预处理、特征工程、模型的所有待调参数)
    param_grid = {
        # 调优PCA:是否降维?降维到多少?(None表示不降维)
        'pca__n_components': [None, 5, 6, 7],  # None即保留原始8维特征
        # 调优随机森林:树的数量
        'rf__n_estimators': [50, 100],
        # 调优随机森林:树的最大深度(控制复杂度)
        'rf__max_depth': [None, 10, 20]
    }
    
    # 4. 网格搜索:用5折交叉验证评估所有参数组合
    grid_search = GridSearchCV(
        estimator=pipe,
        param_grid=param_grid,
        cv=5,  # 5折交叉验证
        scoring='r2',  # 回归任务用R²评分
        n_jobs=-1,  # 并行计算
        verbose=1  # 输出调参过程(可选)
    )
    
    # 5. 执行搜索(自动完成:每折训练集标准化→PCA→模型训练,并评估)
    grid_search.fit(X_train, y_train)
  3. 提取最优结果并验证

    python 复制代码
    # 1. 最优参数组合
    print("最佳参数组合:\n", grid_search.best_params_)
    # 示例输出:{'pca__n_components': None, 'rf__max_depth': None, 'rf__n_estimators': 100}
    # 解读:不做PCA降维,随机森林用100棵树,不限制深度时性能最优
    
    # 2. 最优模型的交叉验证得分
    print("交叉验证最佳R²:", grid_search.best_score_.round(4))  # 示例:0.8056
    
    # 3. 用最优模型在测试集评估(泛化能力验证)
    best_model = grid_search.best_estimator_
    y_pred = best_model.predict(X_test)
    print("测试集R²:", r2_score(y_test, y_pred).round(4))  # 示例:0.8123(与交叉验证得分接近,无过拟合)
  4. 分析参数对性能的影响(可选)

    通过网格搜索的结果,可分析不同参数如何影响模型性能:

    python 复制代码
    import pandas as pd
    
    # 将交叉验证结果转为DataFrame
    results = pd.DataFrame(grid_search.cv_results_)
    
    # 筛选关键列:参数组合、平均得分、排名
    key_results = results[['params', 'mean_test_score', 'rank_test_score']].sort_values('rank_test_score')
    
    # 显示前5个最优参数组合
    print("\n前5个最优参数组合:")
    print(key_results.head())

    输出结果:

    mathematica 复制代码
    最佳参数组合:
     {'pca__n_components': None, 'pca__svd_solver': 'full', 'rf__max_depth': None, 'rf__n_estimators': 100}
    交叉验证最佳R²: 0.731
    测试集R²: 0.7194
    
    前5个最优参数组合:
                                                   params  ...  rank_test_score
    1   {'pca__n_components': None, 'pca__svd_solver':...  ...                1
    7   {'pca__n_components': None, 'pca__svd_solver':...  ...                1
    11  {'pca__n_components': None, 'pca__svd_solver':...  ...                3
    5   {'pca__n_components': None, 'pca__svd_solver':...  ...                3
    0   {'pca__n_components': None, 'pca__svd_solver':...  ...                5
    
    [5 rows x 3 columns]
    • 若 "pca__n_components=None"(不降维)的得分更高,说明原始特征的信息比降维后更完整;
    • 若 "rf__max_depth=10" 比 "None" 好,说明模型存在过拟合,需要限制树深度。

这种组合将 "数据预处理→特征工程→模型训练→参数优化" 整合为一个可复用的流程,解决了手动调参的三大痛点:信息泄露、步骤繁琐、结果不稳定。记住:任何需要严谨评估和调优的机器学习项目,都应该用这种端到端的自动化流程

相关推荐
Sunhen_Qiletian5 小时前
高性能人工智能目标检测开山篇----YOLO v1算法详解(上篇)
人工智能·深度学习·yolo·目标检测·计算机视觉·目标跟踪
koo3645 小时前
李宏毅机器学习笔记36
人工智能·笔记·机器学习
弗朗凌戈5 小时前
机器学习-导师优选
人工智能·python·机器学习
hans汉斯5 小时前
基于机器学习的商业银行信贷风险评估系统构建与实证研究
大数据·人工智能·爬虫·算法·yolo·机器学习·支持向量机
aneasystone本尊5 小时前
重温 Java 21 之分代式 ZGC
人工智能
深度之眼5 小时前
“LSTM+时间序列异常检测”老树开新花!新玩法=发文密码,快来学呀!
人工智能·机器学习·idea
无敌少年小旋风5 小时前
05-面试解析 Agent 理论 + 实践(Spring AI Alibaba)
人工智能·spring·面试
飞哥数智坊6 小时前
看完 Cursor 2.0,我感觉国产 AI 编程又有希望了
人工智能·ai编程·cursor
wwlsm_zql6 小时前
华为科大讯飞携手,低成本AI革新教育农业应用
人工智能·华为