Scikit-learn Interface
The API every sklearn algorithm shares. fit, transform, predict, Pipeline, ColumnTransformer — understand the interface once and every algorithm becomes obvious.
sklearn has 200+ algorithms. They all work the same way. Learn the pattern once — use any algorithm forever.
Imagine you joined DoorDash's data team on day one. Your lead says: "Try a few different models on this delivery time dataset — linear regression, random forest, maybe a gradient boosted tree. See which one performs best." In any other ML library, each algorithm has a completely different API. Different function names, different parameter conventions, different ways to get predictions. You would spend hours reading documentation for each one.
sklearn solved this problem with a unified interface. Every single algorithm — whether it is a simple linear regression or a complex gradient boosting ensemble — follows the exact same pattern: create the model, call .fit() to train it, call .predict() to use it. Switching from one algorithm to another is literally changing one word in your code and nothing else.
This module teaches you that pattern thoroughly. Once you understand it, you can use any of sklearn's 200+ algorithms without reading the docs for each one. You will also learn Pipeline and ColumnTransformer — the two tools that turn a messy sequence of preprocessing steps into a clean, production-ready, leakage-proof workflow.
Think of sklearn like a set of standardised power tools from the same brand. A drill, a sander, and a circular saw all look different and do different things. But they all have the same battery pack, the same on/off button location, and the same safety mechanism. Once you know how to use one tool in the set, picking up a new one takes two minutes — not two hours.
sklearn's "battery pack" is the estimator interface: every model is an object, .fit() trains it, .predict() uses it, .transform() processes data with it. Same pattern, every time.
Three methods — every sklearn object has these
Every sklearn object — whether it is a model, a scaler, an encoder, or an imputer — is built around three methods. Understanding what each one does and when to call it is the entire sklearn interface.
Not all sklearn objects do the same thing — here is the map
sklearn objects fall into three types. All three share the .fit() method. But what they do with it — and what methods they expose — differs. Knowing which type you are working with prevents a lot of confusion.
Learns from labelled data. Takes both X (features) and y (labels) in fit(). Makes predictions on new X.
Learns statistics from X and transforms X. Does NOT use y during fit(). Changes the shape or values of X.
Both preprocesses AND predicts. Uses y during fit() to make the transformation smarter. TargetEncoder is the main example.
Useful attributes after fit() — what every trained object stores
After calling .fit(), sklearn objects expose attributes (ending in underscore _) that let you inspect what was learned. This underscore convention is universal across all of sklearn — if a variable name ends in _ it was set during .fit().
Switching algorithms by changing one word — this is the entire point
The reason sklearn uses a unified interface is so you can compare multiple algorithms with almost zero extra code. The preprocessing stays identical. The evaluation stays identical. Only the model object changes. This is how data scientists actually work — they run several algorithms and pick the one that performs best.
Pipeline — chain preprocessing and modelling into one object
Every ML workflow has multiple steps: impute missing values, scale numeric features, encode categorical features, then train the model. Without Pipeline you write these as separate steps, manually tracking which scaler was fit on which data — and inevitably making the leakage mistake (fitting on the full dataset instead of just the training fold).
Pipeline chains all steps into one object. When you call pipeline.fit(X_train), it fits each step on the training data automatically. When you call pipeline.predict(X_test), it applies each step's stored statistics — never refitting. Data leakage becomes structurally impossible.
A Pipeline is like an assembly line in a factory. Raw materials (data) enter at one end. Each station performs one operation — wash, cut, assemble, paint. The finished product (predictions) comes out at the other end. The assembly line has a fixed order. Each station knows exactly what state the material is in when it arrives.
Without Pipeline you are doing each factory step manually and carrying the half-finished product between stations yourself — error-prone, slow, and easy to do in the wrong order.
Accessing individual steps inside a fitted Pipeline
ColumnTransformer — apply different transformations to different columns
Real datasets always have mixed column types. Numeric columns need scaling. Categorical columns need encoding. Text columns need tokenisation. ColumnTransformer lets you define a different transformation for each group of columns and applies them all in parallel, then concatenates the results into one matrix.
You define named transformers as a list of tuples: (name, transformer, columns). Each transformer processes its assigned columns independently. The results are concatenated horizontally into one output matrix.
remainder='drop' (default) — columns not listed are dropped. remainder='passthrough' — unlisted columns pass through unchanged.
cross_val_score and GridSearchCV — the evaluation and tuning tools
A single train/test split gives you one estimate of model performance. It might be lucky or unlucky depending on which samples ended up in each set. Cross-validation runs the train/test split multiple times with different splits and averages the results — giving a much more reliable performance estimate. GridSearchCV combines cross-validation with hyperparameter search.
Every common sklearn interface error — explained and fixed
Why the unified interface exists — it is what makes a production pipeline one shippable object
The fit/transform/predict convention is not just a teaching convenience — it is the reason sklearn code can be trusted in production at all. A real training job at a company like DoorDash does not run once in a notebook; it runs on a schedule, every week, against fresh data, on a different machine than the one it was written on. What gets version controlled, serialised, and deployed is not a loose script of separate scaler and encoder objects — it is one Pipeline object, because Pipeline is itself just another estimator with the same .fit() and .predict() methods.
This has a direct, practical consequence: because the entire preprocessing chain and the model live inside one object, saving and loading it is a single line, and there is no way for the scoring service to accidentally use a different scaler than the one training produced — a very common real bug in pipelines that were not built this way.
The same property is what makes hyperparameter search and cross-validation trustworthy rather than merely convenient. Because cross_val_score and GridSearchCV both treat the Pipeline as a single estimator, every fold refits the entire preprocessing chain from scratch on only that fold's training data — which is exactly the guarantee that keeps a reported cross-validation score honest. Teams that skip Pipeline and instead scale the full dataset once before splitting are not saving real effort; they are quietly building in the leakage this interface exists specifically to prevent.
Five things people get wrong about the sklearn interface
The method names are identical, but the assumptions behind them are not. Swapping a scaled linear model for a tree ensemble often means scaling is no longer necessary at all, since trees split on raw thresholds regardless of feature magnitude. Swapping in a model that supports class_weight opens up an imbalance-handling option a previous model did not have. The unified interface means less code has to change when you swap algorithms — as Section 4 demonstrates directly — not that literally nothing about the surrounding pipeline needs reconsidering.
fit_transform() does not just apply a transformation — the fit half genuinely learns new statistics from whatever data it is called on. Calling it on test data recomputes mean, standard deviation, or category lists directly from the test set, which both leaks test information into what is supposed to be an unbiased evaluation and can silently produce different scaling entirely if the test distribution differs even slightly from training. Test data must only ever see .transform(), which reuses the statistics fit() already learned from training data — never its own fit_transform() call.
Almost every real feature-engineering step that is not a plain column-level transformation — a business-specific ratio, a domain-informed outlier clip like the OutlierClipper pattern in the Python-for-ML module, target encoding that needs careful cross-fitting to avoid leakage — ends up as a small BaseEstimator and TransformerMixin subclass specifically so it can live inside a Pipeline. That gets it the same leakage protection, the same get_params()/set_params() support GridSearchCV relies on, and the same serialisation behaviour as every built-in transformer, for a few lines of extra code.
Manual step-by-step code is exactly what creates the classic leakage bug: a scaler fit once on the full dataset before the train/test split, or accidentally refit on validation data inside a cross-validation loop written by hand. Pipeline's real job is removing that opportunity structurally — inside cross_val_score(pipeline, ...), every fold refits the entire chain from scratch using only that fold's training portion, which manually-sequenced code has to painstakingly reproduce and very often does not.
The method name is identical everywhere, but what it computes depends entirely on the estimator type: for a regressor .score() returns R², for a classifier it returns plain accuracy. Accuracy alone is close to meaningless on an imbalanced classification problem — a model that always predicts the majority class can score above 90 percent while being useless. Knowing what a specific estimator's default .score() actually measures, and reaching for precision, recall, or AUC when accuracy would mislead, is part of using the interface correctly rather than trusting the number by name alone.
Scikit-learn interface — 5 questions interviewers actually ask
Because a Pipeline is itself a single estimator, tools like cross_val_score and GridSearchCV treat it as one unit and refit the entire thing — imputer, scaler, encoder, and model — from scratch on only each fold's training portion. Manual code that scales the full dataset once before splitting, or that reuses one fitted scaler across every fold, lets statistics from validation or test data quietly influence training. Pipeline does not add a new capability so much as remove the opportunity to make that mistake, by making "fit only on this fold's training data" the only thing that happens automatically.
I would inherit from BaseEstimator, which gives get_params() and set_params() for free so the transformer works with GridSearchCV, and from TransformerMixin, which gives a default fit_transform() implementation for free. Then I implement three methods myself: __init__ to store hyperparameters only, fit(X, y=None) to compute and store any statistics needed from the training data — using a trailing underscore naming convention for what gets learned — and transform(X) to apply those stored statistics to new data. The OutlierClipper example in the Python-for-ML module is exactly this pattern in nine lines.
fit() only learns and stores statistics from the data it is given — it changes nothing and returns no transformed output. transform() applies previously stored statistics to data without learning anything new from it. fit_transform() is a convenience that does both in one call, sometimes with a small performance benefit, but only for the data the model should learn from. fit() and fit_transform() are the wrong call on test or validation data every time, because both would learn new statistics from data that is supposed to be evaluated, not trained on — transform() is the only correct call there.
I would navigate through the named steps: pipeline.named_steps['preprocessor'] gets the ColumnTransformer, .named_transformers_['num'] gets the numeric sub-pipeline by the name it was registered under, and .named_steps['scaler'] gets the actual StandardScaler instance inside that sub-pipeline. From there .mean_ is the learned attribute. The general pattern — chaining named_steps and named_transformers_ — works for inspecting or debugging any nested step inside a fitted Pipeline, which comes up constantly when something inside a production pipeline needs to be audited.
If the feature is a simple deterministic function of columns already present in a single row — like dividing one column by another — placement usually does not introduce leakage, since no information from other rows is involved. But the same question matters enormously for anything that involves an aggregate: a feature like "average order value for this restaurant" must be computed only from training data and supplied via transform() at prediction time, never recomputed including the test row itself, or the model gets to see a statistic that secretly includes its own answer. Building it as a pipeline step forces that computation to happen correctly, fold by fold, instead of once over the whole dataset by habit.
You now speak sklearn fluently. The next section puts it to work on real data.
fit, predict, transform, Pipeline, ColumnTransformer, cross_val_score, GridSearchCV — these are the seven tools you will use in every single ML project for the rest of your career. You now know all of them.
Section 4 — Data Engineering for ML — begins next. It starts with the messiest part of every real ML project: getting the data in the first place. REST APIs, SQL databases, Parquet files, web scraping — where ML data actually comes from and how to pull it reliably with Python.
Where ML data actually comes from. Pull from REST APIs, query databases, read Parquet files, and scrape web data — all with production-grade Python.
🎯 Key Takeaways
- ✓sklearn has one unified interface shared by all 200+ algorithms. Three methods cover everything: .fit() learns from data, .transform() applies learned transformations, .predict() makes predictions. Learn this pattern once — use any algorithm.
- ✓.fit() must only be called on training data. Never on test data. Calling fit on test data leaks information and makes evaluation metrics optimistically wrong. This is the single most important rule in all of sklearn.
- ✓There are three types of sklearn objects: Estimators (models with fit+predict), Transformers (preprocessors with fit+transform), and objects that are both. After fit(), all learned values are stored as underscore attributes: scaler.mean_, model.coef_, encoder.categories_.
- ✓Pipeline chains multiple steps into one object. It enforces correct fit/transform order automatically, prevents leakage in cross-validation (each fold refits the entire pipeline on its training portion), and lets you swap models by changing one word.
- ✓ColumnTransformer applies different transformations to different column groups in parallel. Numeric columns get scaling, categorical get encoding, ordinal get ordinal encoding — all in one object that sklearn treats as a single transformer.
- ✓GridSearchCV and RandomizedSearchCV find optimal hyperparameters. Always pass a Pipeline to these — never raw data with a separate preprocessing step. Use double underscore syntax to target parameters inside Pipeline steps: model__alpha, preprocessor__num__scaler__with_mean.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.