You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sklearn Pipeline处理加州住房数据集:训练拟合正常但测试数据转换报错问题求助

问题排查与解决方案

根据你的代码描述和训练/测试阶段的行为差异,我梳理了几个最可能导致测试阶段transform报错的原因,以及对应的修复方案:

1. 硬编码衍生特征列名引发的列匹配问题

你的get_columns()函数里硬编码了AddComboFeatures生成的衍生特征(比如population_per_room),虽然训练时add_features步骤确实会生成这些列,但这种耦合方式有两个隐患:

  • 要是后续修改衍生特征的生成逻辑(比如新增/删除列),get_columns()不会自动同步,直接导致ColumnTransformer找不到目标列;
  • 部分sklearn版本中,ColumnTransformer会提前校验列名,哪怕这些列是Pipeline后续步骤生成的,也可能在测试transform阶段触发"列不存在"的错误。

修复方案:动态获取衍生特征列名

不要硬编码衍生列,而是通过自定义Transformer的get_feature_names_out方法动态获取:

def get_columns():
    # 定义原始特征列
    original_numerical = [
        "longitude", "latitude", "housing_median_age",
        "total_rooms", "total_bedrooms", "population",
        "households", "median_income"
    ]
    original_categorical = ["ocean_proximity"]
    
    # 从AddComboFeatures中动态获取衍生列名
    combo_transformer = AddComboFeatures()
    all_combo_features = combo_transformer.get_feature_names_out(original_numerical)
    derived_features = [col for col in all_combo_features if col not in original_numerical]
    
    # 定义需要对数转换的列(原始列+指定衍生列)
    log_like_columns = [
        "total_rooms", "total_bedrooms", "population",
        "households", "median_income",
        "population_per_room", "income_per_house", "income_per_population"
    ]
    # 剩余数值列(原始列+未被对数转换的衍生列)
    numerical_columns = original_numerical + derived_features
    remaining_columns = [col for col in numerical_columns if col not in log_like_columns]
    
    return log_like_columns, remaining_columns, original_categorical

2. Pipeline输出格式不统一导致的类型错误

你的preprocess_data函数里调用了pipeline.set_output(transform="pandas")确保输出是DataFrame,但测试代码里直接用features.get_pipeline()生成的Pipeline没有设置这个参数,默认输出是numpy数组。如果后续代码期望处理DataFrame,就会触发类型错误。

修复方案:统一设置Pipeline输出为DataFrame

修改get_pipeline()函数,在返回前统一配置输出格式:

def get_pipeline():
    log_like_columns, remaining_columns, categorical_columns = get_columns()
    log_transformer = FunctionTransformer(
        log_transform, inverse_func=inv_log_transform, validate=False
    )
    log_and_scale = Pipeline(
        [("log_transform", log_transformer), ("scale_transform", StandardScaler())]
    )
    full_pipeline = Pipeline(
        [
            (
                "add_features",
                Pipeline(
                    [
                        ("add_censored_cols", AddCensoredFeatures()),
                        ("add_combo_cols", AddComboFeatures()),
                    ],
                ),
            ),
            (
                "preprocessing",
                ColumnTransformer(
                    [
                        ("log_and_scale_lognormal", log_and_scale, log_like_columns),
                        ("scale_normal", StandardScaler(), remaining_columns),
                        (
                            "categorical_encoder",
                            OneHotEncoder(sparse_output=False),
                            categorical_columns,
                        ),
                    ],
                    remainder="passthrough",
                    verbose_feature_names_out=False  # 顺便禁用列名前缀,避免后续手动处理
                ),
            ),
        ]
    )
    # 全局设置输出为DataFrame
    full_pipeline.set_output(transform="pandas")
    return full_pipeline

3. 自定义train_test_split函数的列缺失问题

你的测试代码用了自定义的train_test_split(df_housing),如果这个函数没有正确保留所有特征列(比如误删了AddComboFeatures依赖的total_rooms等列),就会在transform阶段触发ValueError: The following columns are missing。

修复方案:验证测试数据的列完整性

在测试代码里添加列检查逻辑:

train_X_raw, train_labels, test_X_raw, test_labels = train_test_split(df_housing)
# 检查测试数据是否包含所有必填列
required_cols = ["total_rooms", "total_bedrooms", "population", "median_income", "households"]
missing_cols = [col for col in required_cols if col not in test_X_raw.columns]
if missing_cols:
    raise ValueError(f"测试数据缺失必填列: {missing_cols}")

如果确实存在列缺失,需要修复自定义的train_test_split函数,确保分割时保留所有特征列。

4. 手动修改列名引发的Pipeline复用问题

你的preprocess_data函数里手动去除了ColumnTransformer生成的列名前缀(比如log_and_scale_lognormal__total_rooms改成total_rooms),但这个操作是在fit_transform之后做的,并没有修改Pipeline内部的列名映射。如果后续复用Pipeline或直接用pipeline.transform,会导致训练数据和测试数据的列名不一致,引发错误。

修复方案:禁用ColumnTransformer的列名前缀

上面的get_pipeline()修改中已经添加了verbose_feature_names_out=False参数,这个参数会让ColumnTransformer直接输出原始列名,无需再手动分割处理,彻底避免列名不一致的问题。


内容的提问来源于stack exchange,提问作者Caitlin Kubina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 06:40:29