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

使用imblearn Pipeline替代sklearn Pipeline时文本特征消失的解决方法

问题根因

文本特征丢失是三个逻辑问题叠加导致的,和imblearn本身兼容性无关:

  • 嵌套的文本处理子Pipeline用了sklearn原生版本,内部自定义的FunctionTransformer没配置特征名透传规则,imblearn Pipeline在采样前做特征元数据校验时,识别不到CountVectorizer动态生成的高维文本特征,会默认过滤掉没有合法元数据的特征块。
  • 你给SMOTENC传的分类特征索引是硬编码的[4,5,6,7],但ColumnTransformer的输出顺序是先拼分类特征、再拼文本特征,且OneHotEncoder会把每个分类特征展开成多列(比如3取值的特征会展开成2-3列),4个原始分类特征最终输出的列数远大于4,硬编码的索引会直接指到文本特征块,甚至在索引越界时直接截断后面的文本特征。
  • 你提前在文本子Pipeline里把TF-IDF的稀疏输出转成了稠密数组,旧版本imblearn处理高维稠密输入时,会因为元数据长度和数组实际列数不匹配,丢弃长度校验不通过的特征块。
修正方案

按以下规则调整代码即可解决问题:

  • 嵌套的文本处理子Pipeline也换成imblearn的Pipeline,保证全链路元数据传递逻辑一致
  • 给自定义FunctionTransformer补充特征名透传配置,让上层转换器能识别动态生成的文本特征
  • 不要硬编码SMOTENC的分类特征索引,等预处理层拟合后自动计算分类特征的位置
  • 把稀疏转稠密的步骤移到SMOTENC采样之后,避免采样阶段处理高维稠密数组触发校验错误
  • 预处理阶段保持稀疏矩阵输出,减少内存占用

修正后的可运行代码如下:

from imblearn.pipeline import Pipeline 
from sklearn.preprocessing import OneHotEncoder, FunctionTransformer
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import SGDClassifier
from imblearn.over_sampling import SMOTENC
import numpy as np

vectorizer_params = dict(ngram_range=(1, 2), min_df=200, max_df=0.8)

categorical_features = ['F1','F2','F3','F4']
# sklearn版本低于1.2时,把sparse_output参数改为sparse=False
categorical_transformer = OneHotEncoder(handle_unknown="ignore", sparse_output=False)

textual_feature = ['F5']
# 嵌套子Pipeline统一使用imblearn的Pipeline
text_transformer = Pipeline(
    steps=[
        # 配置特征名透传规则
        ("squeez", FunctionTransformer(
            lambda x: x.squeeze(),
            feature_names_out='one-to-one'
        )),
        ("vect", CountVectorizer(**vectorizer_params)),
        ("tfidf", TfidfTransformer()),
        # 移除此处转稠密数组的步骤,采样完成后再做转换
    ]
)

preprocessor = ColumnTransformer(
    transformers=[
        ("cat", categorical_transformer, categorical_features),
        ("txt", text_transformer, textual_feature),
    ],
    sparse_threshold=1.0 # 预处理阶段保持稀疏输出,降低内存占用
)

# 动态计算分类特征索引,禁止硬编码
# 实际运行时将X_train替换为你的训练集特征即可
# base_prep = Pipeline([("preprocessor", preprocessor)])
# base_prep.fit(X_train, y_train)
# cat_col_count = base_prep.named_steps['preprocessor'].named_transformers_['cat'].get_feature_names_out().shape[0]
# cat_indices = list(range(cat_col_count))
# 调试阶段可临时替换为上面动态计算得到的实际索引值
cat_indices = list(range(4))

sgd_log_pipeline = Pipeline(
    [
        ("preprocessor", preprocessor),
        ('smote', SMOTENC(random_state=11, categorical_features=cat_indices)),
        # 采样完成后再转稠密数组,适配分类器输入要求
        ("toarray", FunctionTransformer(
            lambda x: x.toarray() if hasattr(x, 'toarray') else x, 
            accept_sparse=True
        )),
        ("clf", SGDClassifier()),
    ]
)
注意事项
  • 绝对不要硬编码categorical_features的索引:OneHotEncoder输出的列数由每个分类特征的不同取值数量决定,4个原始分类特征最终展开的列数基本不可能刚好是4,硬编码索引必然导致SMOTENC处理逻辑出错。
  • 运行前检查F5文本列的格式,确保列内所有值都是字符串类型,不存在空值被转成浮点数的情况,否则squeeze步骤会把数据转成通用对象数组,导致CountVectorizer报错。
  • 如果内存足够,可以把sparse_threshold设为0,让ColumnTransformer直接输出稠密数组,但会显著增加内存占用,不推荐在文本特征维度较高时使用。

内容的提问来源于stack exchange,提问作者Ahmad Abdel-Hafez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 11:01:40