Handling Imbalanced Datasets in Machine Learning: Practical Techniques That Work
// outline
Imbalanced datasets are one of the most common — and most misunderstood — challenges in machine learning. When one class appears far more frequently than others, standard training approaches produce models that look accurate on paper but fail in the real world. This guide explains how to handle imbalanced datasets effectively using data-level techniques, algorithm-level solutions, and practical best practices.
What Is an Imbalanced Dataset?
A dataset is considered imbalanced when the distribution of classes is uneven — one class (the majority class) dominates while another (the minority class) appears rarely. The model learns to predict the majority class almost exclusively, making it blind to the rare but often critical minority cases.
// CLASS DISTRIBUTION — REAL-WORLD EXAMPLES
// in all these cases the minority class is the class that actually matters most to the business.
Why Standard Accuracy Is Misleading
Accuracy measures the percentage of correct predictions. In imbalanced datasets it provides a false sense of model performance. If 99% of samples belong to one class, a model that always predicts that class achieves 99% accuracy — while completely ignoring the minority class.
This is why imbalanced learning requires precision, recall, F1-score, and ROC-AUC — metrics that account for each class separately rather than pooling them into a single number.
6 Core Techniques at a Glance
There is no universal fix. The right technique depends on dataset size, imbalance severity, and the business cost of each error type. Here are the six main approaches:
Duplicate minority class samples to increase their count.
Remove majority class samples to shrink the imbalance.
Synthesise new minority samples by interpolating between neighbours.
Penalise misclassifying minority samples more heavily during training.
Combine multiple learners to reduce bias toward the majority class.
For <1% minority — treat the problem as outlier detection instead.
Data-Level Approaches: Resampling
Resampling techniques modify the dataset itself before model training, bringing class counts closer to parity. They are the most commonly used starting point.
Random Oversampling
Increases minority class samples by duplicating existing data points randomly. Simple to implement and works with any algorithm, but risks overfitting because the model sees identical copies of the same samples.
Random Undersampling
Reduces majority class samples by randomly removing data points. Fast and effective on very large datasets, but discards potentially useful information about the majority class.
- Simple to implement with any algorithm
- Works as a strong baseline before advanced methods
- No changes to the model architecture needed
- Supported directly in imbalanced-learn
- Oversampling can cause overfitting on duplicate samples
- Undersampling may discard useful majority class information
- Neither addresses the underlying data distribution
- Must be applied after train-test split to avoid leakage
SMOTE: Synthetic Minority Oversampling Technique
SMOTE is an advanced oversampling method that creates synthetic minority samples by interpolating between existing ones — rather than duplicating them. This reduces overfitting while improving minority class coverage.
Select a Minority Data Point
Pick any sample from the minority class as the starting point for synthesis.
Find Its k Nearest Neighbours
Identify the k closest minority samples in the feature space (default k=5).
Interpolate a New Synthetic Sample
Generate a new point along the line segment connecting the original to a randomly chosen neighbour: new = original + λ × (neighbour − original) where λ ∈ [0,1].
Repeat Until Balance is Achieved
Continue generating synthetic samples until the desired minority class ratio is reached. Common targets: 1:1, 1:2, or 1:5 depending on the problem.
Algorithm-Level Solutions
Instead of modifying the dataset, algorithm-level approaches change how the model learns — making them leakage-free and often more elegant for production pipelines.
Class Weighting and Cost-Sensitive Learning
Class Weighting
Assign higher penalty to misclassifying minority samples. The model is trained to focus disproportionately on getting minority class predictions right.
- Use class_weight='balanced' in sklearn for automatic calculation
- Or specify manually: class_weight={0:1, 1:10}
- Supported by Logistic Regression, SVM, Random Forest, XGBoost
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
# ── Automatic balancing ──────────────────────────────────
lr = LogisticRegression(class_weight='balanced', max_iter=1000)
lr.fit(X_train, y_train)
# ── Manual weighting (minority 10× more important) ───────
rf = RandomForestClassifier(
class_weight = {0: 1, 1: 10},
n_estimators = 200,
n_jobs = -1
)
rf.fit(X_train, y_train)
# ── XGBoost — use scale_pos_weight ──────────────────────
# scale_pos_weight = count(negative) / count(positive)
import xgboost as xgb
xgb_model = xgb.XGBClassifier(
scale_pos_weight = 99, # for 99:1 imbalance
eval_metric = 'aucpr'
)
Ensemble Methods for Imbalanced Classification
BalancedRandomForest & BalancedBaggingClassifier
Ensemble methods from imbalanced-learn that combine resampling with ensemble learning. Each tree is trained on a balanced bootstrap sample, reducing bias toward the majority class.
- BalancedRandomForest — undersamples majority in each bootstrap
- EasyEnsemble — combines multiple AdaBoost with undersampling
- Generally more robust than single-model approaches on skewed data
from imblearn.over_sampling import SMOTE
from imblearn.ensemble import BalancedRandomForestClassifier
from imblearn.pipeline import Pipeline
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.metrics import classification_report
# ── SMOTE pipeline (safe from leakage) ──────────────────
pipeline = Pipeline([
('smote', SMOTE(random_state=42, k_neighbors=5)),
('clf', BalancedRandomForestClassifier(
n_estimators = 200,
random_state = 42,
n_jobs = -1))
])
# ── Stratified k-fold (preserves class ratio per fold) ───
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(pipeline, X, y,
cv=cv, scoring='f1')
print(f"F1 CV mean : {scores.mean():.4f}")
print(f"F1 CV std : {scores.std():.4f}")
# ── Fit and evaluate on holdout ──────────────────────────
pipeline.fit(X_train, y_train)
print(classification_report(y_test, pipeline.predict(X_test)))
// wrapping SMOTE in a Pipeline ensures it only runs on training folds — never on the validation fold. This prevents data leakage.
When Imbalanced Classification Becomes Anomaly Detection
Anomaly Detection for Extreme Imbalance (<1%)
When the minority class is extremely rare, traditional classification may not be suitable. Anomaly detection approaches identify unusual patterns rather than learning class boundaries directly.
- Isolation Forest — isolates outliers by random splits; efficient on high-dimensional data
- One-Class SVM — learns the boundary of normal samples, flags everything outside as anomaly
- Local Outlier Factor (LOF) — density-based; flags points in sparse regions as anomalies
- Autoencoders — deep learning approach; high reconstruction error = anomaly
Choosing the Right Evaluation Strategy
Handling imbalanced datasets is incomplete without proper evaluation. Never use accuracy alone. Use metrics that reflect the business cost of each error type:
Full Python Workflow
A complete end-to-end pipeline using imbalanced-learn — install with pip install imbalanced-learn:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (classification_report,
roc_auc_score,
average_precision_score)
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline
from collections import Counter
# ── 1. Load data ─────────────────────────────────────────
df = pd.read_csv("fraud_data.csv")
X, y = df.drop('fraud', axis=1), df['fraud']
print("Class distribution:", Counter(y))
# ── 2. Stratified split ──────────────────────────────────
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2,
stratify=y, # preserves class ratio
random_state=42
)
# ── 3. SMOTE + classifier pipeline ───────────────────────
model = Pipeline([
('smote', SMOTE(random_state=42)),
('clf', RandomForestClassifier(
class_weight = 'balanced',
n_estimators = 300,
n_jobs = -1,
random_state = 42))
])
# ── 4. Train ─────────────────────────────────────────────
model.fit(X_train, y_train)
# ── 5. Evaluate — never use accuracy! ────────────────────
y_pred = model.predict(X_test)
y_proba = model.predict_proba(X_test)[:, 1]
print(classification_report(y_test, y_pred, digits=4))
print(f"ROC-AUC : {roc_auc_score(y_test, y_proba):.4f}")
print(f"PR-AUC : {average_precision_score(y_test, y_proba):.4f}")
Technique Comparison
| Technique | Modifies data? | Overfitting risk | Info loss? | Best for |
|---|---|---|---|---|
| Random Oversampling | Yes | High | No | Quick baseline |
| Random Undersampling | Yes | Low | Yes | Very large datasets |
| SMOTE | Yes (synthetic) | Medium | No | Moderate imbalance |
| Class Weighting | No | Low | No | Most classifiers |
| Ensemble Methods | Internally | Low | No | Production systems |
| Anomaly Detection | No | Low | No | Extreme imbalance <1% |
Decision Flowchart: Which Technique to Use?
Practical Tips & Common Pitfalls
Apply resampling AFTER the train-test split. Resampling before splitting leaks synthetic minority samples into the test set, inflating metrics and producing misleading results.
Never resample before cross-validation folds. SMOTE must be inside the Pipeline so it only runs on training folds. Resampling the full dataset first contaminates all folds.
Always use StratifiedKFold for cross-validation. Regular KFold can produce folds with no minority samples at all, causing NaN F1 scores and misleading variance estimates.
Do not use accuracy as your primary metric. Use F1, PR-AUC, and ROC-AUC. Align your chosen metric with the business cost of false positives vs false negatives for your specific problem.
Combining techniques thoughtfully. SMOTE + class_weight + ensemble together can sometimes over-correct and introduce noise. Evaluate each combination with proper CV before committing.
Balancing alone does not guarantee better performance. The effectiveness depends on data quality, chosen method, degree of imbalance, and correct evaluation strategy. Always measure both train and validation performance.
FAQs
How do you handle imbalanced datasets in machine learning?
Use a combination of techniques: resampling (oversampling or undersampling), synthetic data generation like SMOTE, class weighting, and ensemble methods. Always evaluate with F1, ROC-AUC, and PR-AUC — never accuracy alone.
Should resampling be applied before or after train-test splitting?
Always after splitting. Resampling before splitting causes data leakage — synthetic samples from the minority class appear in both train and test sets, inflating your evaluation metrics and producing models that fail in production.
What is the difference between random oversampling and SMOTE?
Random oversampling duplicates existing minority samples, creating identical copies. SMOTE creates new synthetic samples by interpolating between existing ones, reducing overfitting and generally producing better generalisation.
Which evaluation metrics work best for imbalanced data?
Precision, Recall, F1-Score, ROC-AUC, and PR-AUC. PR-AUC is particularly informative for severe imbalance because ROC-AUC can appear optimistically high even when recall is poor.
When is undersampling a good choice?
Undersampling works well when the dataset is very large and removing some majority class samples does not result in significant information loss. It is also faster and avoids creating synthetic data.
Which ML models perform well on imbalanced data?
Tree-based ensemble models (Random Forest, XGBoost, LightGBM) generally perform best because they support class weighting natively and their ensemble nature reduces bias toward the majority class.
Does balancing a dataset guarantee better model performance?
No. Balancing does not guarantee better results. Effectiveness depends on the degree of imbalance, data quality, the chosen technique, and correct evaluation. Always measure carefully with cross-validation.
Which Python libraries handle imbalanced datasets?
imbalanced-learn (imblearn) is the primary library — it provides SMOTE, BalancedRandomForest, EasyEnsemble, and integrates with sklearn Pipelines. scikit-learn provides class weighting support. XGBoost and LightGBM offer scale_pos_weight for built-in handling.
How do you handle multiclass imbalance?
Use class_weight='balanced' in sklearn classifiers, apply per-class SMOTE resampling strategies from imbalanced-learn, and evaluate with macro-averaged F1 and per-class precision/recall reports.
Is collecting more data always the best solution?
Collecting more minority class data is ideal but often expensive or impractical in domains like fraud or rare diseases. Algorithmic techniques and resampling are usually more realistic solutions for production systems.
Conclusion
There is no universal solution for handling imbalanced datasets. The best approach depends on the degree of imbalance, dataset size, model type, and the cost of misclassification in your specific domain.
In practice, effective solutions combine multiple strategies:
- Start simple — try class weighting before adding resampling complexity
- Use Pipelines — keep SMOTE inside CV to prevent leakage
- Evaluate correctly — F1, PR-AUC, and ROC-AUC, never accuracy alone
- Match to business goals — if missing a fraud case costs 10× more than a false alarm, optimise recall, not F1
By understanding and applying these strategies correctly, machine learning models become more reliable, fair, and genuinely useful in real-world applications where the minority class is the class that matters most.
Khalid Hussain
Founder of Review Publically. Writes hands-on guides on data science, machine learning and AI tools, testing every model and library before recommending it.
// related reads