Numeric model features often arrive in different units, such as ages, income amounts, and activity counts. StandardScaler in scikit-learn puts each numeric column on a zero-mean, unit-variance scale so scale-sensitive estimators do not let the largest-unit feature dominate model fitting.
StandardScaler learns the mean and standard deviation during fit() and stores them in mean_ and scale_. Fit the scaler on training rows only, then reuse transform() for validation, test, and future rows so evaluation data does not change the training statistics.
Standardization is a preprocessing choice for numeric columns, not a replacement for handling outliers or categorical values. Extreme values affect the mean and standard deviation, while mixed tabular data usually belongs in a ColumnTransformer or Pipeline so every preprocessing step is fitted with the estimator consistently.
Steps to standardize features with scikit-learn:
- Create standardize_features.py with training rows, one held-out row, a scaler, and a small classifier.
- standardize_features.py
import numpy as np import sklearn from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler feature_names = ["age_years", "annual_income", "monthly_visits"] X_train = np.array( [ [22, 38000, 4], [25, 42000, 5], [47, 88000, 7], [52, 92000, 8], [31, 58000, 6], [45, 76000, 7], [28, 54000, 5], [39, 69000, 6], ], dtype=float, ) y_train = np.array([0, 0, 1, 1, 0, 1, 0, 1]) X_holdout = np.array([[34, 62000, 6]], dtype=float) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_holdout_scaled = scaler.transform(X_holdout) model = LogisticRegression(max_iter=1000, random_state=0) model.fit(X_train_scaled, y_train) prediction = model.predict(X_holdout_scaled) def display_zero(value): return 0.0 if abs(value) < 5e-12 else value print(f"scikit-learn {sklearn.__version__}") print("Scaler learned on training rows only:") print(f"- rows_seen: {int(scaler.n_samples_seen_)}") print( "- mean_: " + ", ".join( f"{name}={value:.2f}" for name, value in zip(feature_names, scaler.mean_) ) ) print( "- scale_: " + ", ".join( f"{name}={value:.2f}" for name, value in zip(feature_names, scaler.scale_) ) ) print() print("Scaled training columns:") for name, mean, std in zip( feature_names, X_train_scaled.mean(axis=0), X_train_scaled.std(axis=0) ): print(f"- {name}: mean={display_zero(mean):.6f}, std={std:.6f}") print() print("Scaled holdout row:") for name, value in zip(feature_names, X_holdout_scaled[0]): print(f"- {name}: {value:.3f}") print() print(f"Holdout prediction from scaled features: {prediction.tolist()}")
The scaler uses fit_transform() only on X_train. The held-out row uses transform() so its values are scaled with the training means and standard deviations.
- Run the standardization script.
$ python standardize_features.py scikit-learn 1.9.0 Scaler learned on training rows only: - rows_seen: 8 - mean_: age_years=36.12, annual_income=64625.00, monthly_visits=6.00 - scale_: age_years=10.45, annual_income=18781.22, monthly_visits=1.22 Scaled training columns: - age_years: mean=0.000000, std=1.000000 - annual_income: mean=0.000000, std=1.000000 - monthly_visits: mean=0.000000, std=1.000000 Scaled holdout row: - age_years: -0.203 - annual_income: -0.140 - monthly_visits: 0.000 Holdout prediction from scaled features: [0]
- Confirm the fitted scaler learned statistics from the eight training rows.
Scaler learned on training rows only: - rows_seen: 8 - mean_: age_years=36.12, annual_income=64625.00, monthly_visits=6.00 - scale_: age_years=10.45, annual_income=18781.22, monthly_visits=1.22
- Check that each scaled training column is centered and scaled.
Scaled training columns: - age_years: mean=0.000000, std=1.000000 - annual_income: mean=0.000000, std=1.000000 - monthly_visits: mean=0.000000, std=1.000000
StandardScaler uses the fitted training statistics for each feature, so the transformed training columns print zero means and unit standard deviations.
- Verify the held-out row was transformed without refitting the scaler.
Scaled holdout row: - age_years: -0.203 - annual_income: -0.140 - monthly_visits: 0.000 Holdout prediction from scaled features: [0]
For cross-validation or production prediction, place StandardScaler inside a Pipeline with the estimator so each split fits preprocessing only on its own training fold.
- Remove the scratch file when the smoke check is complete.
$ rm standardize_features.py
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.