Many models care about feature scale. Units in the tens and prices in the tens of thousands would let the large column dominate. StandardScaler subtracts the mean and divides by the standard deviation. Fit it on train only.
Goal
Scale train and test without leaking test statistics, then compare coefficients.
Fit on train, transform both
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = make_classification(n_samples=200, n_features=4, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=0
)
scaler = StandardScaler()
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)
print("train mean", X_train_s.mean(axis=0).round(3))
print("train std ", X_train_s.std(axis=0).round(3))
print("test mean ", X_test_s.mean(axis=0).round(3))Train means sit near 0. Test means are close, not exact — that is expected.
fit_transform
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
X, y = make_classification(n_samples=200, n_features=4, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=0
)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
clf = LogisticRegression(max_iter=200)
clf.fit(X_train_s, y_train)
print("accuracy:", round(accuracy_score(y_test, clf.predict(X_test_s)), 3))
print("coef", clf.coef_.round(3))fit_transform on train is fit then transform. On test, only transform.
Pitfall
scaler.fit(X) on all rows, including test, leaks information. The test set must look like future data the scaler has never seen.