ML Systems Lab Open interactive version →
Foundational 35 min read scalingstandardizationnormalizationrobust scalingdata leakage

Feature Scaling

Ensure features are on comparable scales so that gradient descent, distance metrics, and regularization work correctly.

You are building a k-nearest-neighbours model with two features: age (0 to 100) and annual income (0 to 500,000). To decide who is "nearest," kNN adds up the squared differences on each feature. But look at the numbers: two people can differ by at most 100 in age, and by up to 500,000 in income. Income's differences are thousands of times larger, so they utterly dominate the sum — the age feature becomes effectively invisible. "Nearest neighbour" quietly comes to mean "most similar income," and age is ignored — not because age does not matter, but purely because it is measured in smaller units.

That is the whole problem feature scaling solves: put every feature on a comparable scale so none of them dominates just because of its units. The fix is to rescale each column, and there are three common ways to do it.


Three scalers

StandardScaler subtracts the mean and divides by the standard deviation, so each feature ends up centred at 0 with a spread of 1. Great for roughly bell-shaped data — but sensitive to outliers: one customer earning 10 million yanks the mean and inflates the spread, squashing everyone else toward zero.

MinMaxScaler squeezes each feature into the range 0 to 1. Handy when the zero point matters (word counts, on/off flags), but *even more* outlier-sensitive: the one giant value becomes exactly 1.0 and everyone else is crushed near 0.

RobustScaler uses the *median* and the middle-50% spread — the interquartile range (IQR), the span between the 25th and 75th percentiles — instead of the mean and standard deviation. A lone 10-million earner does not budge the median, so the other 99,999 people get scaled sensibly. It is the safe default when real-but-extreme values are present.


When it matters, and when to skip it

Scaling is essential whenever a model measures *distances* or is sensitive to feature *magnitude*: kNN, K-Means and other distance-based clustering, SVMs, PCA, gradient-descent-trained linear/logistic regression, and neural networks. (For K-Means, the reason is the same as kNN's: cluster assignment is decided by Euclidean distance, so a large-range feature like income dominates the distance calculation and a small-range feature like age is effectively ignored. For linear and logistic regression trained by gradient descent, an unscaled huge-range feature produces gradient updates on a completely different scale than a small-range feature, so a single learning rate is too large for one and too small for the other — the optimizer crawls instead of converging cleanly; standardizing puts every feature's gradient on a comparable footing. Regularised linear models add a second, separate reason on top of that: fairness — the penalty judges coefficients by size, and an income coefficient is naturally tiny next to an age coefficient, so without scaling the penalty hits them unequally. For neural nets, wildly different input scales make the gradients lurch and training unstable.)

You can skip scaling for tree-based models — they only compare thresholds ("is income above 40,000?"), which does not care about units at all. Skip it for plain 0/1 flags too (standardising a yes/no column is meaningless).


The one rule you cannot break: fit the scaler on training data only

Compute the mean, median, and spread from the *training* rows, then apply that same transformation to the test rows. Fit the scaler on everything at once and the test set's statistics leak into training, and your offline numbers come out flatteringly wrong. Wrap it in a pipeline so this happens automatically, every time.


Sparse data: don't destroy the zeros

A subtle trap: StandardScaler mean-centers, and on a *sparse* matrix (TF-IDF text, one-hot features that are mostly zero) subtracting the mean turns all those zeros into small non-zero numbers — the matrix becomes dense, which can explode memory from megabytes to gigabytes. The fix is to scale *without* centering: `StandardScaler(with_mean=False)` or MaxAbsScaler (divides by the max absolute value, leaving zeros as zeros). When your features are sparse, preserving sparsity matters more than centering — never mean-center a large sparse matrix.


Neural networks: scale drives training stability

For neural nets, scaling isn't just about fairness — it's about whether training works at all. Wildly different input scales make the gradient magnitudes wildly different across weights, so a single learning rate is too big for some and too small for others (the condition-number problem at the input layer). Large-magnitude inputs also push saturating activations (sigmoid/tanh) into their flat zones where gradients die, and make training learning-rate-sensitive and unstable. Standardised inputs keep gradients well-behaved from the first step — which is why scaling is effectively mandatory for neural nets, more so than the "fairness" reason for linear models.


Scaling changes PCA materially — it's not cosmetic

PCA finds directions of maximum *variance*, so on unscaled data the components are dominated by whichever feature happens to have the largest units (income in dollars swamps age in years). Scale the features first and the principal components can come out completely different — this isn't a minor adjustment, it changes what PCA "discovers." So standardise before PCA unless you have a specific reason to let high-variance features dominate. (This is why the PCA lesson calls standardisation non-negotiable.)


Sometimes scale the target, too

Scaling usually means the *inputs*, but for regression and neural nets it can help to scale the target as well — a target ranging in the millions produces huge losses and gradients that destabilise training, while a standardised target keeps the loss well-conditioned. The catch: you must inverse-transform the predictions back to the original units before computing business metrics or reporting, or your errors are in the wrong scale. Fit the target scaler on training targets only, same as any other transform.


Outliers before scaling

RobustScaler tolerates outliers, but sometimes even it isn't enough — a handful of values many orders of magnitude out will still distort a distance metric or a neural net. Then treat the outliers *before* scaling: winsorize or clip to a sensible percentile (e.g. cap at the 99th), or apply a log/sqrt transform to compress a heavy right tail. The order matters — transform/clip first, then scale the tamed distribution.


In practice: scale numeric columns only, inside a pipeline

Real datasets mix continuous and categorical/binary columns, and you don't scale them the same way. The standard tool is a ColumnTransformer: scale the numeric columns, one-hot/target-encode the categoricals, and leave 0/1 flags as they are — all in one object. Wrapped in a Pipeline, every transform is fit inside each CV fold on the training portion only, which makes the fit-on-train-only rule structural rather than something you have to remember. Scaling a one-hot column or a binary flag is meaningless; the ColumnTransformer is how you apply scaling to exactly the columns that need it.

Key points

Takeaway

Unscaled features hand large-magnitude inputs disproportionate control over distance metrics, gradient steps, and regularization penalties — not because they are more important, but because they are measured in larger units.

Recap

Check your understanding

Q1. You fit a StandardScaler on your entire dataset (train + test combined) before splitting. What exactly is wrong?

Q2. A K-Means clustering of customer data with features [age (range 20-80), annual_income (range 20,000-200,000)] produces clusters entirely separated by income and ignores age. Why and fix?

Q3. You are doing 5-fold cross-validation and you fit a MinMaxScaler on the full training set before the CV loop. What is the consequence?

Q4. Why does applying StandardScaler to inputs of a random forest not improve performance, while applying it to logistic regression typically does?

Q5. You apply StandardScaler to a large sparse TF-IDF matrix and your job runs out of memory. Which TWO of the following correctly explain why and what the fix is?

Q6. You're training a neural network to predict house prices that range up to several million. Training is unstable and the loss occasionally explodes. Beyond scaling the inputs, what else should you consider, and what must you not forget?

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →