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

如何在Scikit-Learn Pipeline中正确集成SMOTE处理类别不平衡

SMOTE接入Scikit-Learn生态Pipeline的正确方式

核心规则(必守,否则结果无效)

  • 禁止在train_test_split之前应用SMOTE:否则测试集样本会混入训练采样过程,造成严重数据泄露,验证结果完全失真。
  • 不要使用Scikit-Learn原生Pipeline承载SMOTE:SMOTE是同时修改特征矩阵X和标签y的重采样组件,sklearn原生Pipeline仅支持前置步骤输出单份特征矩阵,无法兼容重采样逻辑,需要使用imbalanced-learn库提供的Pipeline。该Pipeline会自动控制SMOTE仅在训练fit阶段对训练集生效,预测阶段不会对测试集做任何采样处理,从机制上规避泄露。
  • 禁止在预处理步骤之前插入SMOTE:SMOTE基于样本距离生成少数类新样本,未填充的缺失值、未编码的分类特征、未缩放的数值特征都会导致距离计算完全失效,生成的样本无实际意义。

正确的Pipeline步骤顺序:列预处理器(缺失值填充/分类编码/数值缩放) → SMOTE过采样 → 分类模型

现有代码的其他问题

  • 任务类型错配:当前是欺诈检测二分类任务,模型列表中混入了RandomForestRegressor回归模型,不适用于分类场景。
  • 评估指标错配:r2_score是回归任务专属指标,不适合分类任务,尤其类别不平衡场景下,应该优先使用F1、Recall、ROC-AUC这类对少数类敏感的分类指标。
  • 数据集拆分未做分层:原拆分逻辑没有保证训练、测试集的类别比例与原数据集一致,容易引入额外偏差。

修正后可运行代码

首先安装必要依赖:
pip install imbalanced-learn

from collections import Counter
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OrdinalEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
# 导入imblearn的Pipeline
from imblearn.pipeline import Pipeline as ImbPipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import LinearSVC
from sklearn.metrics import f1_score, recall_score, roc_auc_score

df_n = df[['user_id','signup_day', 'signup_month', 'signup_year', 
    'purchase_day', 'purchase_month', 'purchase_year','purchase_value',
    'source','browser','sex','age', 'is_fraud']]

X = df_n.drop(['is_fraud'], axis=1)
y = df_n.is_fraud

# 拆分时增加stratify参数,保证训练测试集类别分布一致
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)
print(Counter(y_train)) # 输出Counter({0: 95844, 1: 9934})

numeric_transformer = Pipeline(steps=[
       ('imputer', SimpleImputer(strategy='mean')),
       ('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
       ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
       ('encoder', OrdinalEncoder(handle_unknown='use_encoded_value', unknown_value=-1))
])

numeric_features = ['user_id','signup_day', 'signup_month', 'signup_year',
        'purchase_day', 'purchase_month', 'purchase_year','purchase_value', 'age']
categorical_features = ['source', 'browser', 'sex']

preprocessor = ColumnTransformer(
   transformers=[
    ('numeric', numeric_transformer, numeric_features),
    ('categorical', categorical_transformer, categorical_features)
]) 

# 替换为全部分类模型
classifiers = [
    RandomForestClassifier(random_state=42, n_jobs=-1),
    LogisticRegression(max_iter=1000, random_state=42, n_jobs=-1),
    DecisionTreeClassifier(random_state=42),
    KNeighborsClassifier(n_jobs=-1),
    LinearSVC(random_state=42, dual=False)
]

for clf in classifiers:
    # 用imblearn的Pipeline构建流程,SMOTE插入在预处理器之后、分类器之前
    pipeline = ImbPipeline(steps = [
               ('preprocessor', preprocessor),
               ('smote', SMOTE(random_state=42)),
               ('classifier', clf)
           ])
    model = pipeline.fit(X_train, y_train)
    predictions = model.predict(X_test)
    print(clf)
    # 重点关注少数类(欺诈标签=1)的识别效果
    print(f"F1 Score: {f1_score(y_test, predictions, pos_label=1):.4f}")
    print(f"Fraud Class Recall: {recall_score(y_test, predictions, pos_label=1):.4f}")
    # 支持概率输出的模型计算ROC AUC
    if hasattr(clf, "predict_proba"):
        proba = model.predict_proba(X_test)[:,1]
        print(f"ROC AUC: {roc_auc_score(y_test, proba):.4f}")
    print("-"*60)

额外优化建议

  • 如果普通SMOTE效果不理想,可以尝试SMOTE的变体如BorderlineSMOTE、SVMSMOTE,这类方法对边界少数类样本的生成质量更高,更适配欺诈检测这类正负类边界模糊的场景。
  • 可以搭配模型的class_weight='balanced'参数使用,从算法层面进一步提升对少数类的权重,多数场景下效果会优于单独使用SMOTE。
  • user_id属于用户唯一标识,不具备泛化预测价值,建模时可以考虑从特征列表中移除,避免模型学到无意义的ID对应规律。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:12:19