求助:含文本与分类特征的数据集如何正确应用SMOTE解决类别不平衡
解决文本+多特征场景下SMOTE与Pipeline整合问题
问题根源分析
你之前的方案存在两个核心问题:
- 未处理非文本的分类特征:
ColumnTransformer仅对description做了TF-IDF向量化,但其他分类特征如果是字符串格式,remainder='passthrough'会直接保留原格式,SMOTE无法处理非数值特征,导致采样逻辑异常甚至静默失效。 - 对ImbPipeline的采样逻辑理解偏差:ImbPipeline会自动在模型拟合前对训练数据执行采样,但前提是所有输入特征都是数值型,且采样策略配置正确。
正确解决方案
1. 统一预处理所有特征
用ColumnTransformer批量处理不同类型的特征:文本特征做TF-IDF向量化,分类特征做独热编码,数值特征直接保留。
示例代码:
from sklearn.compose import ColumnTransformer from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.preprocessing import OneHotEncoder # 替换为你的实际特征列名 text_cols = ['description'] cat_cols = ['category1', 'category2'] num_cols = ['num_feature1', 'num_feature2'] # 构建预处理管道 column_transformer = ColumnTransformer( transformers=[ ('tfidf', TfidfVectorizer(max_features=5000), text_cols), # 限制特征数避免高维问题 ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False), cat_cols) ], remainder='passthrough', # 直接保留数值特征 verbose_feature_names_out=False # 生成简洁特征名(可选) )
2. 构建正确的ImbPipeline
按「预处理→SMOTE→分类器」的顺序组装管道,同时配置SMOTE的采样策略:
from imblearn.pipeline import ImbPipeline from imblearn.over_sampling import SMOTE from sklearn.ensemble import RandomForestClassifier # 初始化SMOTE与分类模型 smote = SMOTE( sampling_strategy='auto', # 默认将少数类采样至与多数类数量一致;多分类可手动指定比例 k_neighbors=5, random_state=42 ) rf_model = RandomForestClassifier(n_estimators=100, random_state=42) # 完整管道 pipeline = ImbPipeline([ ('preprocessing', column_transformer), ('smote', smote), ('classifier', rf_model) ])
3. 验证SMOTE生效
拟合后可手动检查采样前后的类别分布,确认SMOTE是否正常工作:
from collections import Counter # 拟合管道 pipeline.fit(X_train, y_train) # 获取预处理后的特征矩阵并应用SMOTE X_processed = pipeline.named_steps['preprocessing'].transform(X_train) X_resampled, y_resampled = pipeline.named_steps['smote'].fit_resample(X_processed, y_train) # 打印类别分布对比 print("原始训练集类别分布:", Counter(y_train)) print("SMOTE采样后类别分布:", Counter(y_resampled))
4. 合理评估模型
类别不平衡场景下准确率无参考价值,需用F1-score、召回率、混淆矩阵等指标评估:
from sklearn.metrics import classification_report from sklearn.model_selection import cross_val_score # 分层交叉验证(适配类别不平衡) cv_scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring='f1_macro', n_jobs=-1) print("交叉验证F1分数均值:", cv_scores.mean()) # 测试集评估 y_pred = pipeline.predict(X_test) print(classification_report(y_test, y_pred))
常见失效排查点
如果SMOTE仍未生效,检查以下内容:
- 所有特征是否已转换为数值型:可通过
column_transformer.transform(X_train).dtype验证; - SMOTE的
sampling_strategy是否匹配你的类别分布(多分类场景需手动指定); - 是否误用了普通
Pipeline而非ImbPipeline:普通Pipeline不会自动在训练阶段应用采样器。
内容的提问来源于stack exchange,提问作者CyrilKhoneiser
相关产品推荐
相关产品推荐

