Features measured in unrelated units can pull a scale-sensitive estimator toward the columns with the largest numeric ranges. StandardScaler in scikit-learn centers each numeric feature around zero and scales it to unit variance so magnitude reflects the data rather than its original unit.
The scaler learns one mean and scale per feature during fit(). Fit those statistics from training rows only, then reuse transform() for held-out and future rows so information outside the training set cannot influence preprocessing.
Standardization does not reduce the influence of outliers, and centering is unsuitable for sparse matrices unless densifying them is acceptable. Mixed numeric and categorical columns normally belong in a ColumnTransformer, while a Pipeline keeps the fitted preprocessing attached to the estimator during cross-validation and prediction.
import numpy as np 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, ) X_holdout = np.array([[34, 62000, 6]], dtype=float)
Every array uses the same column order. Each row represents one sample, and each column represents one feature.
scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) fitted_mean = scaler.mean_.copy() X_holdout_scaled = scaler.transform(X_holdout)
fit_transform() learns from X_train and scales those rows. transform() applies the stored statistics to X_holdout without fitting again.
np.testing.assert_allclose(X_train_scaled.mean(axis=0), 0.0, atol=1e-12) np.testing.assert_allclose(X_train_scaled.std(axis=0), 1.0, atol=1e-12) np.testing.assert_array_equal(scaler.mean_, fitted_mean) def format_values(values): return "[" + ", ".join(f"{value:.3f}" for value in values) + "]" print(f"training rows: {scaler.n_samples_seen_}") print(f"learned means: {format_values(scaler.mean_)}") print(f"learned scales: {format_values(scaler.scale_)}") print(f"scaled training means: {format_values(X_train_scaled.mean(axis=0))}") print(f"scaled training standard deviations: {format_values(X_train_scaled.std(axis=0))}") print(f"scaled holdout row: {format_values(X_holdout_scaled[0])}") print("training statistics unchanged after holdout transform: yes")
The assertions stop the program if the training features are not centered and scaled or if transforming the held-out row changes the fitted means.
$ python standardize_features.py training rows: 8.0 learned means: [36.125, 64625.000, 6.000] learned scales: [10.446, 18781.224, 1.225] scaled training means: [-0.000, -0.000, 0.000] scaled training standard deviations: [1.000, 1.000, 1.000] scaled holdout row: [-0.203, -0.140, 0.000] training statistics unchanged after holdout transform: yes