BitBootcampBitBootcamp ← all explainers 🔄 Review ⚙ Settings

ML-01-003-P · Primer — Your First Model: The fit/predict API

The idea in one sentence

Every model in scikit-learn is an object you teach with .fit(X, y) and then ask with .predict(X) — same two verbs, every time.

Why it exists

Machine learning could have been a chaos of one-off functions, each with its own name, argument order, and quirks — a fresh manual to read for every algorithm. Instead, scikit-learn made a deliberate design choice: wrap every algorithm in an estimator object that speaks the same tiny vocabulary. Learning from data is always .fit(X, y). Making a guess on new data is always .predict(X). This uniformity is why you can swap a decision tree for a logistic regression by changing one line, and why every tutorial, notebook, and production pipeline in the ecosystem feels familiar. Master this one pattern and you have effectively learned the interface to hundreds of models at once.

How it works

Think of an estimator as an empty student: you create it, it learns from examples, then it answers questions. First you organize your data as X (a 2-D table of features, one row per example) and y (the labels you want to predict). You create the estimator object, call .fit(X, y) so it absorbs the pattern, and store what it learned inside itself. Then .predict(X_new) returns a guess for rows it has never seen. The exact math differs between models, but the two verbs never change — that is the whole trick.

from sklearn.tree import DecisionTreeClassifier

# Tiny inline dataset: [size, weight] -> fruit (0 = grape, 1 = apple)
X = [[1, 1], [1, 2], [2, 2], [8, 7], [9, 8], [8, 9]]
y = [0, 0, 0, 1, 1, 1]

model = DecisionTreeClassifier(random_state=0)  # 1. create the estimator
model.fit(X, y)                                 # 2. teach it from examples

pred = model.predict([[1, 1], [9, 9]])          # 3. ask about new fruit
print(pred)                                     # -> [0 1]  (grape, apple)
print(model.score(X, y))                        # -> 1.0  (perfect on training data)

The one gotcha

X must be 2-D — a list of rows, even for a single example. Passing one flat sample like model.predict([9, 9]) raises a shape error; scikit-learn reads that as one feature across many samples, not one sample with many features. Always wrap it: model.predict([[9, 9]]). When in doubt, remember the shape is (n_samples, n_features) — rows are examples, columns are features.

See it — the universal train-then-predict loop

flowchart TD
    A["Raw examples<br/>(features X, labels y)"] --> B["Create estimator<br/>model = Model(...)"]
    B --> C["model.fit(X, y)<br/>learn the pattern"]
    C --> D["Trained model<br/>(knowledge stored)"]
    E["New unseen data<br/>X_new"] --> F["model.predict(X_new)<br/>ask for a guess"]
    D --> F
    F --> G["Predictions<br/>(labels out)"]

The one-line takeaway

Two verbs run all of scikit-learn: .fit() to learn, .predict() to guess — everything else is just picking which estimator to put in front of them.

Where you'll meet it

You will use this exact pattern in every notebook of this course and every ML job in the wild: classifiers, regressors, clustering, and full preprocessing pipelines all expose .fit() and .predict(). Once it is muscle memory, the deep AIM track builds straight on top of it — cross-validation, hyperparameter tuning, and production pipelines are all just orchestrations of these same two calls.

Named concepts: estimator objects, .fit(), .predict()