Picture a fraud-detection model that scores 99.8% accuracy. Impressive, right? Now picture the same model catching exactly zero fraud cases. That contradiction sits at the heart of one of machine learning’s sneakiest traps: class imbalance.
This article is the companion guide to Episode 27 of the Intelevo Machine Learning Series on YouTube. In the video, we unpack this problem step by step, with a running analogy and live code. Here, you’ll find the same journey in text form, so you can read at your own pace, copy the code, and revisit the formulas whenever you need them.
By the end, you’ll know why accuracy fails on imbalanced data, how to measure model performance honestly, and which resampling technique fits your situation. You’ll also learn the one ordering mistake that quietly invalidates entire projects, along with a faster alternative that doesn’t touch your data at all. Let’s dive in.
What Makes a Dataset “Imbalanced”?
A dataset becomes imbalanced when one outcome vastly outnumbers the other. Data scientists call the common outcome the majority class. They call the rare, usually more important outcome the minority class.
Consider a typical fraud dataset. Legitimate transactions make up 99.8% of the data. Fraudulent transactions make up just 0.2%. That tiny sliver is exactly what your model exists to catch, yet it barely shows up in the training data.
This pattern repeats across industries. In healthcare, most patients test negative for any single condition. In manufacturing, defective parts stay rare by design. In customer analytics, most customers stick around, and only a handful churn. Wherever a rare, high-stakes outcome hides inside a sea of normal cases, you’re dealing with imbalance.
Meet the Lifeguard: A Simple Way to Think About Imbalance
Before we get technical, let’s build an intuition. Picture yourself as a lifeguard watching a crowded beach. Almost every swimmer stays safe. Only a rare few actually get into trouble.
If you miss that one struggling swimmer, your overall “accuracy” barely changes. After all, you were still right about everyone else. But that single miss is the one that actually mattered.
That’s the exact trap imbalance sets for a machine learning model. Throughout this guide, we’ll return to this lifeguard whenever a new idea needs grounding. It keeps the math connected to something real.
Why Accuracy Lies to You
Here’s where the paradox becomes concrete. Imagine you build a “lazy” model with scikit-learn’s DummyClassifier. Instead of learning anything, it simply predicts whichever class appears most often.
from sklearn.dummy import DummyClassifier
lazy = DummyClassifier(strategy="most_frequent")
lazy.fit(X_train, y_train)
print(lazy.score(X_test, y_test))
# 0.998 → looks perfect...
print(lazy.predict(X_test).sum())
# 0 → ...caught zero fraud cases
Notice the gap. The accuracy score looks flawless. However, the model never predicts fraud, not even once. If accuracy were the only metric you checked, this model would sail through review while doing nothing useful.
So, what should you check instead? That question leads directly to better metrics.
Better Questions: Precision, Recall, and F1
Instead of asking “how often am I right overall,” ask two sharper questions. Together, they reveal what accuracy hides.
Precision asks: of everyone you called a rescue, how many really needed one?
Precision = TP / (TP + FP)
Recall asks: of everyone who really needed a rescue, how many did you actually catch?
Recall = TP / (TP + FN)
Precision and recall often pull in opposite directions. Therefore, data scientists combine them into a single balanced score called the F1 score:
F1 Score = 2 × (Precision × Recall) / (Precision + Recall)
This is the one formula worth memorizing from this whole guide. Fortunately, you rarely need to calculate it by hand. Scikit-learn’s classification_report() prints precision, recall, and F1 for every class automatically.
Once you can measure the problem honestly, you can start fixing it. That brings us to resampling.
Three Ways to Balance the Odds
Once you understand the imbalance, you can treat it directly. The three most common techniques all work by changing the data your model trains on, not the algorithm itself.
- Undersampling trims the majority class down.
- Oversampling duplicates the minority class up.
- SMOTE generates new, synthetic minority examples.
Let’s walk through each one, with code you can copy straight into your own notebook.
Method 1: Undersampling the Majority
Undersampling works like sending some calm, well-supervised swimmers home early. Fewer majority-class rows remain, so the rare struggler no longer gets drowned out.
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_res, y_res = rus.fit_resample(X_train, y_train)
print(y_train.value_counts())
# 0: 99800 1: 200
print(y_res.value_counts())
# 0: 200 1: 200
This approach shines on very large datasets, where you can afford to drop rows and still have plenty left. On the other hand, you’re throwing away real data. Useful patterns can disappear right along with it, so proceed carefully on smaller datasets.
Method 2: Oversampling the Minority
Oversampling flips the strategy. Instead of removing majority rows, it repeats minority rows until the model can’t help but notice them. Every duplicate represents a real case, just shown more often.
from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(random_state=42)
X_res, y_res = ros.fit_resample(X_train, y_train)
print(y_train.value_counts())
# 0: 99800 1: 200
print(y_res.value_counts())
# 0: 99800 1: 99800
This method suits smaller datasets, where you can’t afford to lose majority-class rows. However, exact copies can push a model toward memorizing instead of generalizing. Keep an eye on overfitting when you use this technique.
Method 3: SMOTE — Synthetic Minority Oversampling
SMOTE takes oversampling a step further. Rather than copying existing rows, it invents new, realistic examples. Specifically, it picks a real minority point, finds a nearby minority neighbor, and creates a new point somewhere on the line between them.
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_res, y_res = smote.fit_resample(X_train, y_train)
print(y_res.value_counts())
# 0: 99800 1: 99800
# each new '1' sits between two real
# minority points, not a copy of either
You don’t need a complicated formula here. Just remember the core idea: SMOTE invents a believable in-between case instead of repeating an old one. That said, it needs numeric features, and it can blur class boundaries when the minority points themselves are noisy.
SMOTE also has several variants worth knowing by name, even if you don’t use them today. Borderline-SMOTE focuses new points near the decision boundary, where classification errors happen most often. ADASYN, meanwhile, generates more synthetic points for minority examples that are harder to learn. Both build on the same core idea, so once SMOTE clicks for you, these variants become easy extensions rather than new concepts.
Choosing the Right Fix
No single method wins every time. Instead, the right choice depends on your dataset size and how much data you can afford to lose or invent.
| Method | Best When | Tradeoff | Typical Data Size |
|---|---|---|---|
| Undersample | You have plenty of majority rows to spare | Loses real data and possible patterns | Large datasets |
| Oversample | You can’t afford to lose majority rows | Risk of overfitting on repeats | Small to medium |
| SMOTE | You want variety, not repetition | Needs numeric features; can blur edges | Small to medium |
If your dataset is huge, undersampling is fast and simple. If it’s small, oversampling or SMOTE protects your limited majority-class data. Meanwhile, SMOTE generally produces the most realistic training signal, as long as your features stay numeric.
A Faster Alternative: class_weight
Resampling changes your data. Sometimes, though, you’d rather leave the data alone and adjust the algorithm instead. Many scikit-learn models accept a class_weight parameter for exactly this purpose.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(class_weight="balanced")
model.fit(X_train, y_train)
Setting class_weight="balanced" tells the model to penalize mistakes on the minority class more heavily. Consequently, the model pays closer attention to rare cases during training. It never adds, removes, or invents a single row.
This approach works well as a quick baseline, since it requires no extra library and no resampling step at all. Still, it doesn’t help every algorithm, and it won’t fix a dataset that’s imbalanced by orders of magnitude. In those cases, combining class_weight with a resampling technique often produces the strongest results.
The One Mistake That Undoes Everything
Here’s the part many tutorials skip. It’s also the single most common mistake in this entire workflow: resampling the whole dataset before splitting it into train and test sets.
Why does the order matter so much? If you resample first, SMOTE’s synthetic points can leak into your test set. As a result, your model ends up tested on data shaped by itself. That gives you a test score you simply can’t trust.
The fix is straightforward. First, split your data. Then, resample only the training portion.
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
X_res, y_res = smote.fit_resample(X_train, y_train) # train only!
This way, your test set stays untouched and honest. It reflects the real-world imbalance your model will actually face once it’s deployed. Keep this rule close: split first, resample second, always.
Where This Shows Up in the Real World
Class imbalance isn’t a theoretical problem. It shapes real decisions across industries.
- Healthcare analytics relies on recall for rare-disease screening. Missing one true case costs far more than a false alarm ever would.
- Banking and fraud detection deals with imbalance directly. Fraud represents a tiny slice of all transactions.
- Retail and e-commerce platforms flag rare events, like returns or defective shipments, buried inside millions of normal orders.
- Cybersecurity teams hunt for intrusions that hide like a needle in a haystack of ordinary network traffic.
Wherever a rare, high-stakes outcome hides inside a mountain of normal data, this toolkit applies directly.
Frequently Asked Questions
Does class imbalance always need fixing? Not always. If your model already achieves strong precision and recall on the minority class, leave it alone. Fix imbalance only when your metrics reveal an actual problem, not by default.
Which technique should a beginner try first? Start with class_weight="balanced", since it takes one line of code and touches no data. From there, move to SMOTE if you need a bigger performance boost.
Can I combine multiple techniques together? Yes, and practitioners often do. A common pattern pairs moderate undersampling of the majority class with SMOTE on the minority class, striking a balance between speed and data preservation.
Does imbalance affect deep learning too? Absolutely. Neural networks are just as vulnerable to the accuracy trap. The same fixes apply, though frameworks like PyTorch and TensorFlow expose class weighting through slightly different APIs.
Quick Recap: What You Can Now Do
Let’s tie everything together. First, you can spot the accuracy trap. A rare class can make accuracy meaningless, so reach for precision, recall, and F1 instead.
Second, you can resample the right way. Choose undersampling, oversampling, or SMOTE, and always apply it after the train-test split, never before.
Third, you can match the method to your dataset. Undersample when data is abundant. Oversample or use SMOTE when it’s scarce.
Finally, you can avoid data leakage. Keep your test set untouched and honest, so it reflects the imbalance your model will meet in production.
Together, these four skills form a complete toolkit for one of the most common real-world problems in machine learning.
What’s Next
Handling imbalanced datasets only works when it rests on a clean, honest train-test split. That’s exactly where Episode 28 picks up. Next time, we’ll cover data splitting strategies in depth, along with an introduction to cross-validation, so every score you report is a score you can trust.
Watch the full walkthrough, with live code and visuals, in the Episode 27 video on the Intelevo YouTube channel. If this guide helped clarify the topic, consider subscribing so you don’t miss Episode 28. Full episode notes always live here on intuitivetutorial.com, so bookmark this page and check back for updates as the series continues.
