scikit-learn fit, transform and predict: keep learned state inside training
Run an imputer-scaler-classifier pipeline, inspect fitted statistics and verify that prediction does not refit preprocessing on held-out data.
fit learns an estimator's state from data. transform applies a learned representation, and predict produces a model output. In a pipeline, training fits the preprocessing steps and then the final model; prediction transforms new input with the stored state before using that model.
The distinction matters even for simple preprocessing. A mean imputer and a standard scaler learn numerical quantities from the training set. Calculating them from the full dataset leaks information from the evaluation population into the fitted workflow.
Follow one invented train/test split
Our training table has one feature, four records and one missing value. The held-out table contains a very large value and a missing value. The unusual test value makes leakage visible: a full-data mean would differ from the training-only mean.
This is a fixed teaching split chosen to inspect API behavior, not an estimate of model quality. A real experiment needs an evaluation design matching the prediction population, time boundaries and class frequencies.
The pipeline explicitly names its steps. After fitting, inspect named_steps to confirm which statistics were learned. A pipeline does not automatically fix target leakage or a bad split, but it keeps these fitted preprocessing operations together with the estimator during training and evaluation.
import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
X_train = np.array([[0.], [2.], [np.nan], [4.]])
y_train = np.array([0, 0, 1, 1])
X_test = np.array([[100.], [np.nan]])
model = make_pipeline(SimpleImputer(), StandardScaler(),
LogisticRegression(C=1., solver='lbfgs'))
model.fit(X_train, y_train)
imputer = model.named_steps['simpleimputer']
scaler = model.named_steps['standardscaler']
before = scaler.mean_.copy()
print('training imputer mean:', imputer.statistics_.tolist())
print('training scaler mean:', scaler.mean_.tolist())
print('held-out transformed:', np.round(scaler.transform(imputer.transform(X_test)), 3).ravel().tolist())
print('predictions:', model.predict(X_test).tolist())
print('state unchanged:', np.array_equal(before, scaler.mean_))
print('leaky full-data mean:', float(np.nanmean(np.vstack([X_train, X_test]))))
assert imputer.statistics_[0] == 2
assert np.array_equal(before, scaler.mean_)
Checked output:
training imputer mean: [2.0]
training scaler mean: [2.0]
held-out transformed: [69.296, 0.0]
predictions: [1, 1]
state unchanged: True
leaky full-data mean: 26.5
Know which methods a step supports
A scaler has fit and transform, but it does not classify observations. A classifier has fit and predict; it need not expose transform. The final estimator determines which methods the pipeline can provide. predict_proba is available only when the final estimator supports it.
For a preprocessing step on training data, fit_transform combines learning and transformation. For the held-out table, call transform, not fit_transform. Refitting on the test values changes the coordinate system after the classifier has learned weights in the original one.
The large transformed held-out value is expected. Standardization uses training statistics; it does not promise that all future values fall into a small interval. Treat such a value as a possible distribution or data-quality issue rather than refitting until the number looks comfortable.
Put cross-validation around the whole workflow
Pass the complete pipeline into cross-validation. Each fold then learns its preprocessing state from that fold's training partition. Fitting a scaler once before splitting folds shares information across the fold boundary.
Hyperparameter search uses the same pattern. Keep model selection separate from a final untouched test set, and use group-aware or chronological splits when records are dependent. Cross-validation for groups and time demonstrates why the splitter is part of the experiment.
Test the input contract too
A valid pipeline still needs the expected feature order, units and missing-value conventions. A one-column model cannot infer that a newly supplied column means something different. At a service boundary, check the schema and use the same feature construction as training.
Extend this example with a second feature and verify that both fitted means come only from the training rows. Then compare a fold-specific imputer against the invalid full-data alternative. The Data Tools course connects these APIs to end-to-end modeling, while scaling versus normalization explains which transformation suits a particular geometry.
References
scikit-learn common pitfalls — Consistent preprocessing, data leakage and pipeline use.
Pipeline API — Which methods are supported and how steps are fitted and applied.