0Pricing
Machine Learning Academy · Lesson

Feature Scaling: StandardScaler and MinMaxScaler

Learners will fit StandardScaler and MinMaxScaler to training data, transform test data separately, and understand why fitting on test data causes leakage.

Feature Scaling: StandardScaler and MinMaxScaler is a free Machine Learning Academy lesson on CoddyKit — lesson 2 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.

Why Feature Scaling Matters

Many machine learning algorithms are sensitive to the scale of input features. If one feature spans 0–1000 and another spans 0–1, distance-based models like KNN and SVM will be dominated by the larger-scale feature. Gradient descent algorithms also converge much faster when features share a similar scale. Tree-based models like Random Forests and XGBoost are scale-invariant and do not require scaling, but almost every other algorithm benefits from it.

import numpy as np

# Without scaling: 'income' dominates 'age'
X = np.array([
    [25, 50000],
    [35, 80000],
    [45, 120000]
])

# Distance between row 0 and row 1 (Euclidean)
dist = np.sqrt((25-35)**2 + (50000-80000)**2)
print('Distance dominated by income:', dist)
# age contributes 100, income contributes 900,000,000 to squared distance

StandardScaler: Z-Score Normalisation

StandardScaler transforms each feature to have zero mean and unit variance by applying the formula: z = (x - mean) / std. This is called standardisation or z-score normalisation. The resulting values are centred around 0 with no fixed range. StandardScaler is the default choice for most algorithms including logistic regression, SVMs, and neural networks, especially when the feature distribution is approximately Gaussian.

from sklearn.preprocessing import StandardScaler
import numpy as np

X = np.array([[25, 50000], [35, 80000], [45, 120000]], dtype=float)

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

print('Scaled data:\n', X_scaled)
print('Mean per feature:', X_scaled.mean(axis=0))  # ~[0, 0]
print('Std per feature:', X_scaled.std(axis=0))    # ~[1, 1]

How StandardScaler Stores Statistics

After calling fit(), StandardScaler stores the training-set statistics in scaler.mean_ and scaler.scale_ (standard deviation). These same statistics are used when you call transform() on new data — meaning the test set is scaled using training set parameters, not its own. This is the correct behaviour: in production, you receive individual samples one at a time and must scale them using the statistics computed during training.

from sklearn.preprocessing import StandardScaler
import numpy as np

X_train = np.array([[1, 200], [2, 400], [3, 600]], dtype=float)
X_test  = np.array([[4, 800]], dtype=float)

scaler = StandardScaler()
scaler.fit(X_train)  # Learn mean and std from training data ONLY

print('Learned mean:', scaler.mean_)
print('Learned scale:', scaler.scale_)

X_train_s = scaler.transform(X_train)
X_test_s  = scaler.transform(X_test)  # Uses SAME training statistics
print('Test scaled:', X_test_s)

MinMaxScaler: Rescaling to a Fixed Range

MinMaxScaler compresses each feature to a specified range, typically [0, 1], using the formula: x_scaled = (x - x_min) / (x_max - x_min). Unlike StandardScaler, it preserves the relative shape of the distribution and handles non-Gaussian data well. It is sensitive to outliers: a single extreme value can squish all other values near zero or one. MinMaxScaler is popular for neural networks and image pixel values (scaled to [0, 1]).

from sklearn.preprocessing import MinMaxScaler
import numpy as np

X = np.array([[10], [20], [30], [40], [50]], dtype=float)

scaler = MinMaxScaler(feature_range=(0, 1))
X_scaled = scaler.fit_transform(X)

print('MinMax scaled:', X_scaled.flatten())
# [0.0, 0.25, 0.5, 0.75, 1.0]

# Custom range: scale to [-1, 1]
scaler2 = MinMaxScaler(feature_range=(-1, 1))
print('[-1,1] scaled:', scaler2.fit_transform(X).flatten())

RobustScaler: Handling Outliers

RobustScaler scales using the median and interquartile range (IQR) instead of mean and standard deviation. Because median and IQR are not influenced by extreme values, RobustScaler is a better choice when your data contains significant outliers. The formula is: x_scaled = (x - median) / IQR. Use RobustScaler when you cannot remove outliers and want them to have minimal influence on the scaled values passed to your model.

from sklearn.preprocessing import RobustScaler
import numpy as np

# Data with outlier at 1000
X = np.array([[1], [2], [3], [4], [1000]], dtype=float)

from sklearn.preprocessing import StandardScaler, RobustScaler

std_s = StandardScaler().fit_transform(X)
rob_s = RobustScaler().fit_transform(X)

print('StandardScaler (outlier squishes others):')
print(std_s.flatten())
print('RobustScaler (outlier isolated):')
print(rob_s.flatten())

Choosing the Right Scaler

Here is a quick decision guide: use StandardScaler when your data is roughly Gaussian and you have no extreme outliers — it is the safest default. Use MinMaxScaler when you need values in a fixed range, such as for image data or algorithms that require [0, 1] inputs. Use RobustScaler when outliers are present and meaningful (e.g., financial data with fraud spikes). For tree-based models (Random Forest, XGBoost, LightGBM), skip scaling entirely — it offers no benefit and adds unnecessary complexity.

from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# Decision helper
def pick_scaler(has_outliers, needs_fixed_range, is_tree_model):
    if is_tree_model:
        return 'No scaling needed'
    elif has_outliers:
        return 'RobustScaler'
    elif needs_fixed_range:
        return 'MinMaxScaler'
    else:
        return 'StandardScaler'

print(pick_scaler(False, False, False))  # StandardScaler
print(pick_scaler(True, False, False))   # RobustScaler
print(pick_scaler(False, True, False))   # MinMaxScaler
print(pick_scaler(False, False, True))   # No scaling needed

Fitting on Test Data: The Leakage Trap

A common mistake is calling fit_transform() on the test set, which computes a new mean and standard deviation from test data. This is a form of data leakage because the scaler is influenced by test-set values. The correct pattern is: fit(X_train)transform(X_train)transform(X_test). Even a small accuracy improvement from this leak can lead to overconfident production deployments that fail on truly unseen data.

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import numpy as np

X = np.random.randn(100, 3)
y = (X[:, 0] > 0).astype(int)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

scaler = StandardScaler()

# CORRECT: fit on train, transform both
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s  = scaler.transform(X_test)

# WRONG (leakage):
# scaler.fit_transform(X_test)  <- never do this

Scaling Inside a Pipeline

The cleanest way to avoid scaling leakage is to embed the scaler inside a scikit-learn Pipeline. When the pipeline is fitted with cross_val_score or GridSearchCV, each fold fits the scaler only on the training portion of that fold. The test fold is never touched during fitting. This is the production-ready pattern: preprocessing and modelling steps are bundled together, making deployment as simple as calling pipeline.predict(X_new).

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('clf', LogisticRegression(max_iter=200))
])

# Scaler fitted only on train fold in each CV iteration
scores = cross_val_score(pipe, X, y, cv=5)
print('CV accuracy:', scores.mean().round(3))

Inverse Transform: Back to Original Scale

After making predictions, you may need to convert predictions back to the original scale — for example, a house-price model trained on log-scaled prices must output prices in dollars. Both StandardScaler and MinMaxScaler provide inverse_transform() to reverse the scaling. Only inverse-transform the target variable when it was scaled before training. Features do not typically need to be inverse-transformed because they are consumed internally by the model.

from sklearn.preprocessing import StandardScaler
import numpy as np

y_train = np.array([100000, 200000, 300000, 400000], dtype=float).reshape(-1, 1)

target_scaler = StandardScaler()
y_scaled = target_scaler.fit_transform(y_train)
print('Scaled target:', y_scaled.flatten())

# After predicting in scaled space:
y_pred_scaled = np.array([[0.5]])
y_pred_original = target_scaler.inverse_transform(y_pred_scaled)
print('Prediction in original scale:', y_pred_original)

Scaling Sparse Data with MaxAbsScaler

Sparse matrices — common in text classification with TF-IDF vectors — should not be scaled with StandardScaler or MinMaxScaler because centering destroys sparsity by making most zeros non-zero, which defeats the purpose of sparse storage. MaxAbsScaler scales each feature by its maximum absolute value, mapping values to the range [-1, 1] without centering, and preserves the sparsity structure. Always use MaxAbsScaler when working with sparse feature matrices from vectorisers like TfidfVectorizer.

from sklearn.preprocessing import MaxAbsScaler
from scipy.sparse import csr_matrix
import numpy as np

# Simulated sparse TF-IDF matrix
X_sparse = csr_matrix(np.array([
    [0, 0.5, 0.3, 0],
    [0.8, 0, 0, 0.4],
    [0, 0.2, 0, 0.6]
]))

scaler = MaxAbsScaler()
X_scaled = scaler.fit_transform(X_sparse)
print('Scaled sparse matrix:\n', X_scaled.toarray())
# All values in [-1, 1], sparsity preserved

Comparing Scalers on Real Data

To see the practical effect of each scaler, compare their output distributions side by side. After scaling, StandardScaler output should be approximately N(0,1), MinMaxScaler output should span [0,1], and RobustScaler output should have median at 0 with IQR of 1. Plotting histograms before and after scaling confirms the transformation worked correctly. Good feature scaling is a prerequisite for reliable model training, not an optional add-on.

import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
import numpy as np

X = np.random.exponential(scale=100, size=(200, 1))  # Skewed data

scalers = {
    'StandardScaler': StandardScaler(),
    'MinMaxScaler': MinMaxScaler(),
    'RobustScaler': RobustScaler()
}

fig, axes = plt.subplots(1, 4, figsize=(16, 4))
axes[0].hist(X, bins=30); axes[0].set_title('Original')
for ax, (name, sc) in zip(axes[1:], scalers.items()):
    ax.hist(sc.fit_transform(X), bins=30)
    ax.set_title(name)
plt.tight_layout()
plt.show()

Quick Check

Test your understanding of Machine Learning with Python concepts from this lesson.

Lesson Recap

In this lesson you learned: why feature scaling is essential for distance-based and gradient-descent algorithms, how StandardScaler standardises to N(0,1) while MinMaxScaler compresses to [0,1], and the critical rule of fitting scalers only on training data to prevent leakage. Next up we explore encoding categorical variables with OrdinalEncoder and OneHotEncoder.

Frequently asked questions

Is the “Feature Scaling: StandardScaler and MinMaxScaler” lesson free?

Yes — the full text of “Feature Scaling: StandardScaler and MinMaxScaler” 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 “Feature Scaling: StandardScaler and MinMaxScaler”?

Learners will fit StandardScaler and MinMaxScaler to training data, transform test data separately, and understand why fitting on test data causes leakage. 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 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Feature Scaling: StandardScaler and MinMaxScaler” 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

  1. Handling Missing Values: Drop, Impute, and Flag
  2. Feature Scaling: StandardScaler and MinMaxScaler
  3. Encoding Categorical Variables: OrdinalEncoder and OneHotEncoder
  4. Combining Steps with ColumnTransformer
← Back to Machine Learning Academy