Feature Scaling & Transforms
Put features on a common scale with StandardScaler, MinMaxScaler, and RobustScaler, and tame skewed distributions with log and power transforms.
A dataset rarely arrives ready for modeling: one column measures age (20–70), another income (thousands to millions), a third is skewed so hard that 95% of values huddle near zero. Many algorithms quietly assume features live on comparable scales — and misbehave when they don't. This lesson covers why scaling matters, which scaler to use when, and how power transforms fix skewed distributions — plus the one mistake (fitting scalers on test data) that silently invalidates your results.
Why scale at all?
Three concrete reasons:
- Gradient descent converges better. Remember in the linear-regression
lesson how
blearned slower thanw? With features of wildly different magnitudes, the loss surface becomes a long, narrow valley: the gradient is steep in one direction and nearly flat in another, so a learning rate that's safe for one weight is glacial for another. Scaling rounds the valley into a bowl, and the same steps reach the bottom far faster. - Distance-based models need it. KNN, K-Means, and SVMs compare points by distance. If income ranges over millions and age over decades, distance is effectively just income — age becomes invisible.
- Regularization must be fair. The next lesson penalizes large weights. But a feature measured in millimeters needs a coefficient 1000× larger than the same feature in meters — penalizing raw coefficient size across unscaled features punishes features for their units, not their usefulness.
(Tree-based models are the notable exception — they split on thresholds and don't care about scale.)
Three scalers, one outlier
scikit-learn's big three:
- StandardScaler — subtract the mean, divide by the standard deviation. Result: mean 0, std 1. The default choice, best when data is roughly bell-shaped.
- MinMaxScaler — shift the minimum to 0, stretch the maximum to 1. Intuitive bounded range, but one outlier squeezes everyone else into a tiny sliver.
- RobustScaler — subtract the median, divide by the interquartile range (IQR). Quantiles barely move when an outlier appears, so it's the scaler of choice for contaminated data.
Watch how a single outlier affects each:
Look at the MinMax row in the dirty block: the outlier grabbed max = 1.0
for itself and crushed all 200 real points below ~0.1 — most of the scale is
wasted on one bad value. StandardScaler suffered too (the outlier inflated
the std, shrinking everyone). RobustScaler's output is nearly identical in
both blocks — the median and IQR barely noticed.
Skewed data: transform before (or instead of) scaling
Scaling shifts and stretches, but it can't change a distribution's shape. Income, prices, trip distances — many real features are right-skewed: a heavy pile near zero and a long tail. Linear models and standardization both work better when values are roughly symmetric. The fix is a nonlinear transform:
- log — the classic for positive right-skewed data (
np.log1phandles zeros). - Box-Cox — a family of power transforms that learns the best exponent; requires strictly positive data.
- Yeo-Johnson — Box-Cox's sibling that also accepts zero and negative
values. scikit-learn's
PowerTransformerdefault.
The raw histogram slumps against zero with a long tail; all three transforms
produce a much more symmetric bell. PowerTransformer even standardizes the
output for you (mean 0, std 1) by default, so it often replaces the
scaler entirely for skewed columns. This works on targets too — if y is
skewed (like the taxi fares in this module's exercises), modeling log(y)
often fixes the funnel-shaped residual plots you learned to spot in lesson 1.
QuantileTransformer, briefly: it maps values to their quantiles, forcing any distribution into a uniform (or normal) shape. It's a blunt but effective instrument for very messy features — just know it's non-linear and rank-based, so it distorts distances within the tails.
Fit on train, transform everywhere
Scalers are learned from data — the mean, the min/max, the quantiles are statistics. If you compute them on the full dataset before splitting, information about the test set bleeds into training. That's data leakage, and it makes your evaluation optimistic.
Never fit a scaler on test data
Always: scaler.fit_transform(X_train) then scaler.transform(X_test) — fit
on train only, reuse those statistics for the test set. The test set must
be processed exactly as truly-new data would be: with statistics it had no
part in computing.
The foolproof way to obey this rule is to put the scaler inside a
Pipeline. Then fit only ever sees training data, cross-validation
re-fits the scaler per fold automatically, and you can't leak even if you try:
From now on in this course, preprocessing always lives inside the pipeline — it's not just tidier, it's the only leak-proof way to work.
Choosing quickly
| Data looks like | Use |
|---|---|
| Roughly bell-shaped | StandardScaler |
| Need a bounded 0–1 range, no outliers (e.g., pixel values) | MinMaxScaler |
| Contains outliers you can't remove | RobustScaler |
| Right-skewed, strictly positive | log / Box-Cox |
| Skewed with zeros or negatives | Yeo-Johnson (PowerTransformer) |
| Bizarre multi-modal mess | QuantileTransformer |
Check your understanding
Q1.Why does feature scaling speed up gradient descent?
Q2.Your feature has a few extreme outliers you can't remove. Which scaler distorts the non-outlier points the least?
Q3.You want to power-transform a feature containing negative values. Which method works?
Q4.A colleague fits StandardScaler on the full dataset, then splits into train/test. What's wrong?
Exercise: Does scaling rescue KNN?
Load load_diabetes and deliberately sabotage it: multiply one feature column
by 1000 so it dominates all distances. Split into train/test, then fit a
KNeighborsRegressor twice — once on the raw sabotaged data, once inside a
Pipeline with StandardScaler. Compare test R². Explain in a comment why
the unscaled version suffers.
With features on a fair, common scale, we can finally penalize model weights fairly too — next: regularization with Ridge, Lasso, and ElasticNet.