Random Undersampling and Cluster Centroids
Learners will undersample the majority class at random and with ClusterCentroids, comparing the information loss and resulting model performance.
Random Undersampling and Cluster Centroids is a free Machine Learning Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Machine Learning Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Undersampling: Reducing the Majority Class
While oversampling grows the minority class, undersampling shrinks the majority class to balance the dataset. The key advantage: training is faster because there is less data overall. The key risk: you discard real majority-class information, potentially causing the model to make more false positives. Undersampling is most useful when the majority class is so large that oversampling would make training prohibitively slow.
Random Undersampling: Delete Majority Examples at Random
RandomUnderSampler randomly selects and removes majority-class samples until the desired ratio is achieved. It is the fastest undersampling method but throws away potentially useful information. With small datasets, random undersampling can make the model significantly worse by discarding majority samples near the decision boundary.
from imblearn.under_sampling import RandomUnderSampler
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05],
n_features=10, random_state=42)
print('Before undersampling:', np.bincount(y))
rus = RandomUnderSampler(sampling_strategy=1.0, random_state=42)
X_res, y_res = rus.fit_resample(X, y)
print('After undersampling:', np.bincount(y_res))
print('New total samples:', len(y_res))Controlling the Sampling Strategy
The sampling_strategy parameter controls the final ratio of minority to majority. 1.0 makes them equal; 0.5 keeps 2:1 majority advantage. For very large datasets you might set 0.1 to create a 10:1 ratio — still better than the original 100:1 while keeping training fast. Choose based on the business cost of false positives vs false negatives.
from imblearn.under_sampling import RandomUnderSampler
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=10000, weights=[0.99, 0.01], random_state=42)
print('Original:', np.bincount(y))
for ratio in [1.0, 0.5, 0.2]:
rus = RandomUnderSampler(sampling_strategy=ratio, random_state=0)
_, y_r = rus.fit_resample(X, y)
counts = np.bincount(y_r)
print(f'ratio={ratio}: {counts} ({counts[1]/counts[0]:.2f} min:maj)')Cluster Centroids: Intelligent Undersampling
ClusterCentroids applies K-Means clustering to the majority class, replacing each cluster with its centroid. Instead of keeping random majority samples, it retains a compressed, representative set. This preserves the overall structure of the majority class better than random deletion, but is slower and requires tuning the number of clusters (which equals the target majority count after resampling).
from imblearn.under_sampling import ClusterCentroids
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.9, 0.1],
n_features=5, random_state=42)
print('Before:', np.bincount(y))
cc = ClusterCentroids(sampling_strategy=1.0, random_state=42)
X_cc, y_cc = cc.fit_resample(X, y)
print('After ClusterCentroids:', np.bincount(y_cc))
print('Note: synthetic centroids replace real majority samples')Comparing Undersampling Methods
Let us benchmark random undersampling vs cluster centroids vs no resampling on the same imbalanced dataset, using F1-score on the minority class as the evaluation metric.
from imblearn.under_sampling import RandomUnderSampler, ClusterCentroids
from imblearn.pipeline import Pipeline as ImbPipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import f1_score
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)
sc = StandardScaler()
X_tr = sc.fit_transform(X_train)
X_te = sc.transform(X_test)
for name, sampler in [('None', None),
('RUS', RandomUnderSampler(random_state=0)),
('ClusterCentroids', ClusterCentroids(random_state=0))]:
if sampler:
Xr, yr = sampler.fit_resample(X_tr, y_train)
else:
Xr, yr = X_tr, y_train
lr = LogisticRegression().fit(Xr, yr)
f1 = f1_score(y_test, lr.predict(X_te))
print(f'{name:20s}: F1={f1:.4f} n_train={len(yr)}')Information Loss in Undersampling
The critical downside of undersampling is information loss. When 95 out of every 100 majority-class samples are discarded, the model sees a training distribution very different from reality. This can inflate false-positive rates in production. For this reason, undersampling is often combined with oversampling (e.g., using SMOTEENN or SMOTETomek) to balance the dataset while minimising information loss.
Combining Oversampling and Undersampling
SMOTETomek combines SMOTE (oversample minority) with Tomek Links removal (clean ambiguous boundary majority samples). The result balances both classes and removes borderline majority samples that confuse the classifier. This combined approach often outperforms either oversampling or undersampling alone.
from imblearn.combine import SMOTETomek
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
print('Before:', np.bincount(y))
st = SMOTETomek(random_state=42)
X_res, y_res = st.fit_resample(X, y)
print('After SMOTETomek:', np.bincount(y_res))Near Miss: Informed Undersampling by Distance
NearMiss selects majority-class samples based on their distance to minority samples — choosing either the closest (NearMiss-1) or the farthest (NearMiss-3). Unlike random undersampling, NearMiss keeps majority samples that are most relevant for defining the decision boundary. NearMiss-3 keeps majority samples farthest from all minority samples, creating a cleaner boundary region.
from imblearn.under_sampling import NearMiss
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.9, 0.1], random_state=42)
print('Before:', np.bincount(y))
for version in [1, 2, 3]:
nm = NearMiss(version=version)
_, y_nm = nm.fit_resample(X, y)
print(f'NearMiss-{version}:', np.bincount(y_nm))Undersampling Inside an imblearn Pipeline
Like oversampling, undersampling must happen inside a pipeline to prevent leakage during cross-validation. Use imblearn.pipeline.Pipeline with the undersampler as a step before the classifier. The sampler's fit_resample is called on each training fold, and test folds are never modified.
from imblearn.pipeline import Pipeline as ImbPipeline
from imblearn.under_sampling import RandomUnderSampler
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
pipe = ImbPipeline([
('sc', StandardScaler()),
('rus', RandomUnderSampler(random_state=42)),
('lr', LogisticRegression())
])
scores = cross_val_score(pipe, X, y, cv=5, scoring='f1')
print(f'CV F1 (RUS): {np.mean(scores):.4f} +/- {np.std(scores):.4f}')When to Choose Undersampling Over Oversampling
Prefer undersampling when: the majority class is enormous (millions of samples), training time is a bottleneck, or computational resources are constrained. Prefer oversampling (SMOTE) when: the minority class is very small (fewer than a few hundred samples), discarding majority data would make the training set too small, or the minority class has complex, non-convex structure that SMOTE can fill in. In practice, try both and compare on validation metrics.
Evaluating After Undersampling
After resampling, always evaluate on the original imbalanced test set — never on a resampled test set. Resampling the test data would give an unrealistic view of production performance. The goal is to improve the model's behaviour on the true data distribution, not to optimise for an artificial balanced distribution.
from sklearn.metrics import classification_report
from imblearn.under_sampling import RandomUnderSampler
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42)
sc = StandardScaler()
X_train_s = sc.fit_transform(X_train)
X_test_s = sc.transform(X_test)
rus = RandomUnderSampler(random_state=0)
X_r, y_r = rus.fit_resample(X_train_s, y_train)
lr = LogisticRegression().fit(X_r, y_r)
# Evaluate on ORIGINAL imbalanced test set
print(classification_report(y_test, lr.predict(X_test_s)))Quick Check
Test your understanding of undersampling and Cluster Centroids from this lesson.
Lesson Recap
In this lesson you learned: RandomUnderSampler randomly deletes majority samples — fast but risks losing important boundary information, ClusterCentroids replaces majority clusters with their centroids to preserve the class distribution more faithfully, and always evaluate on the original imbalanced test set to measure real-world model behaviour. Next up we explore class weighting and threshold moving as alternatives to resampling.
Frequently asked questions
Is the “Random Undersampling and Cluster Centroids” lesson free?
Yes — the full text of “Random Undersampling and Cluster Centroids” is free to read here on the web, and the Machine Learning Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Machine Learning Academy course, upgrade to CoddyKit PRO.
What will I learn in “Random Undersampling and Cluster Centroids”?
Learners will undersample the majority class at random and with ClusterCentroids, comparing the information loss and resulting model performance. You practise Machine Learning Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Machine Learning Academy?
No prior experience is required. Machine Learning Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Random Undersampling and Cluster Centroids” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Machine Learning Academy lesson?
Yes. Every Machine Learning Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Detecting Imbalance: Class Distribution and Baseline Pitfalls
- Random Oversampling and SMOTE
- Random Undersampling and Cluster Centroids
- Class Weights and Threshold Moving