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

Sklearn预处理管道报错ValueError:列'short_model'不存在,求排查

解决Data预处理管道中short_model列不存在的报错

问题根源

ColumnTransformer的工作逻辑是并行独立处理每个transformer指定的列:每个transformer只拿到自己的目标列,处理后输出结果,最后将所有transformer的输出拼接成最终特征矩阵。你在ShortModelTransformer和AgeCategoryTransformer中生成的short_model、age_category列,仅存在于各自transformer的局部DataFrame中,不会被其他transformer(比如categorical)识别到,因此触发列不存在的报错。

另外,自定义transformer中直接修改原DataFrame的操作(如X['year'].loc[...])可能触发SettingWithCopyWarning,建议操作数据副本。

解决方案

把生成新列的特征工程步骤放到前置Pipeline中,先完成所有新特征的生成,再用ColumnTransformer对包含新列的完整DataFrame进行分类处理。

修改后的完整代码

import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer

class CalculateOutliers(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X):
        # 操作副本避免修改原数据
        X_copy = X.copy()
        q25 = X_copy['year'].quantile(0.25)
        q75 = X_copy['year'].quantile(0.75)
        iqr = q75 - q25
        boundaries = (q25 - 1.5 * iqr, q75 + 1.5 * iqr)
        X_copy.loc[X_copy['year'] < boundaries[0], 'year'] = round(boundaries[0])
        X_copy.loc[X_copy['year'] > boundaries[1], 'year'] = round(boundaries[1])
        return X_copy

class ShortModelTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def short_model(self, x):
        if not pd.isna(x):
            return x.lower().split(' ')[0]
        else:
            return x

    def transform(self, X):
        X_copy = X.copy()
        X_copy['short_model'] = X_copy['model'].apply(self.short_model)
        return X_copy

class AgeCategoryTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X):
        X_copy = X.copy()
        X_copy['age_category'] = X_copy['year'].apply(lambda x: 'new' if x > 2013 else ('old' if x < 2006 else 'average'))
        return X_copy

# 前置Pipeline:先完成所有新特征生成
feature_engineering = Pipeline(steps=[
    ('outliers', CalculateOutliers()),
    ('short_model', ShortModelTransformer()),
    ('age_category', AgeCategoryTransformer())
])

# 分类特征处理管道
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('encoder', OneHotEncoder(handle_unknown='ignore', sparse=False))
])

# 数值特征处理管道
numerical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')),
    ('encoder', StandardScaler())
])

# 完整预处理管道:先生成特征,再分类处理
preprocessor = Pipeline(steps=[
    ('feature_gen', feature_engineering),
    ('preprocess', ColumnTransformer(transformers=[
        ('numerical', numerical_transformer, ['year', 'odometer']),
        ('categorical', categorical_transformer, ['fuel', 'title_status', 'transmission',
                                                  'state', 'short_model', 'age_category'])
    ]))
])

关键说明

  • 前置Pipelinefeature_engineering会依次执行所有特征生成步骤,每一步都基于上一步的完整DataFrame,因此short_model和age_category会被添加到全局DataFrame中。
  • 后续的ColumnTransformer拿到的是经过特征工程后的完整DataFrame,可以直接引用新生成的列。
  • 所有自定义transformer都操作DataFrame的副本,避免了原数据被修改和潜在的警告。

内容的提问来源于stack exchange,提问作者Aleksandr Pay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 09:28:17