Back to Blog
Lesson 18 of the Intermediate Machine Learning: Real-World Pipelines course
AI/MLJune 25, 20263 min read

Handling Class Imbalance with Resampling in ML Pipelines

Learn to fix class imbalance using SMOTE and RandomUnderSampler. Master pipeline integration to prevent data leakage and ensure reliable model training.

AI/MLmachine learningpipelinesimbalanced-learnSMOTEdata scienceaimachine-learningpython

Previously in this course, we covered Introduction to Cross-Validation: Robust Model Evaluation and established the importance of Data Leakage Prevention Strategies: Protecting Pipeline Integrity. In this lesson, we address the common real-world problem where your target classes are not represented equally.

Class imbalance occurs when one class (the minority) is significantly less frequent than the others. If you feed an imbalanced dataset into a standard classifier, the model will often achieve high accuracy by simply predicting the majority class every time. Resampling techniques—oversampling the minority class or undersampling the majority class—help balance the decision boundary.

The First Principles of Resampling

Resampling is a transformation that changes the distribution of your training data.

  • RandomUnderSampler: This technique removes samples from the majority class. It is computationally efficient but risks discarding potentially valuable information.
  • SMOTE (Synthetic Minority Over-sampling Technique): Instead of duplicating minority samples, SMOTE creates "synthetic" examples by interpolating between existing minority instances in feature space.

The golden rule here is never resample your validation or test data. If you oversample the entire dataset before splitting, you create "data leakage," where the model "sees" the synthetic points during testing, leading to inflated performance metrics that will collapse in production.

Pipeline Integration with imbalanced-learn

Standard scikit-learn Pipeline objects do not natively support resampling because Pipeline expects each step to have a transform method that returns the same number of rows as the input. Resampling changes the number of rows, which breaks standard pipelines.

To solve this, we use the imblearn.pipeline.Pipeline class, which is a drop-in replacement that handles the sample step correctly during training.

Worked Example: Building a Balanced Pipeline

We will use the imblearn library to build a pipeline that cleans, balances, and predicts.

PYTHON
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler

# Define the pipeline steps
# Note: We use imblearnCE9178">'s Pipeline, not sklearn's
model_pipeline = Pipeline([
    (CE9178">'scaler', StandardScaler()),
    (CE9178">'sampler', SMOTE(sampling_strategy=CE9178">'auto')),
    (CE9178">'classifier', RandomForestClassifier(random_state=42))
])

# The pipeline only resamples during .fit()
# When you call .predict(), the sampler is skipped automatically.
model_pipeline.fit(X_train, y_train)

By placing the sampler inside the pipeline, you ensure that every time you call cross_val_score or perform a grid search, the resampling happens only on the training folds. The validation folds remain untouched, providing an honest assessment of model performance.

Hands-on Exercise

  1. Install imbalanced-learn if you haven't already (pip install imbalanced-learn).
  2. Create a synthetic imbalanced dataset using make_classification(weights=[0.9, 0.1]).
  3. Build a pipeline with SMOTE and a LogisticRegression model.
  4. Evaluate the model using cross_val_score with scoring='f1'. Compare this to a pipeline without SMOTE. Notice the difference in recall.

Common Pitfalls

  • Resampling before splitting: As mentioned, this is the most common error. Always ensure your split happens first. If you are using StratifiedKFold as discussed in our earlier lessons, ensure your resampling happens inside the fold-specific training loop.
  • Over-relying on SMOTE: SMOTE creates noisy data if your minority class is sparse or overlapping with the majority class. Always benchmark a baseline model (no sampling) and a simple RandomUnderSampler before committing to synthetic generation.
  • Pipeline incompatibility: Using sklearn.pipeline.Pipeline instead of imblearn.pipeline.Pipeline will throw an error because the former doesn't know how to handle the changing row counts.

Recap

Handling class imbalance is about adjusting the training distribution to give the model a fair chance to learn the minority class. By using imblearn pipelines, you encapsulate the resampling logic within the training process, effectively preventing data leakage and keeping your evaluation protocol robust.

Up next: Advanced Metrics for Imbalanced Datasets where we move beyond accuracy to metrics like MCC and Cohen's Kappa.

Similar Posts