Part IV — Modeling · Chapter 8

Modeling and Evaluation

~45 min read6 interactive widgets4 plates

In this chapter

  1. The modeling phase of CRISP-DM
  2. What machine learning means: two definitions
  3. Under- and overfitting, from the start
  4. The disclaimer: understand why the model behaves
  5. Types of machine learning
  6. scikit-learn: the workbench
  7. The Estimator API
  8. scikit-learn in action
  9. Supervised learning: classification and regression
  10. The data: feature matrix and target array
  11. Built-in datasets
  12. The Iris dataset, loaded and profiled
  13. Splitting into training and test sets
  14. Randomness, seeds and reproducibility
  15. Why the random_state matters
  16. Check your understanding

1. The modeling phase of CRISP-DM

After business understanding, data understanding and data preparation, the CRISP-DM cycle reaches its center: Modeling. This chapter and the next three follow the deck 6 - Modeling, which is where the course finally trains models — and, as the deck title announces, evaluates them. The whole deck is hands-on: it uses scikit-learn on the Iris dataset, one of the classical benchmarks of machine learning.

CRISP-DM — THE MODELING PHASE Business Understanding Data Understanding Data Preparation Deployment Evaluation Modeling MODELING ● this chapter WHAT THE DECK DOES 1. defines machine learning (two quotes) 2. warns: under- and overfitting 3. types of ML and the sklearn toolbox 4. the Estimator API, fit / predict / score 5. the Iris dataset and the train/test split 6. seeds and reproducibility (why 42?) 7. then: three models, three chapters the modeling phase is a workflow, not a single step
Plate 8.1 — Where we are in the cycle. Modeling sits between prepared data and evaluation; the deck under study turns it into a concrete scikit-learn workflow that the next three chapters unpack model by model.

2. What machine learning means: two definitions

The deck opens the phase with the two classical definitions of machine learning, and both are worth memorizing verbatim:

Machine Learning is the field of study that gives computers the ability to learn without being explicitly programmed.

Arthur Samuel, 1959

A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experience E.

Tom Mitchell, 1997
Key idea

Samuel's sentence gives the spirit — no explicit programming — and Mitchell's gives the contract: experience E, task T, performance measure P. Every model in the next chapters is an answer to Mitchell's contract: the training data is the experience, the prediction is the task, and accuracy is the performance measure.

In the deck, this definition is followed by a single word that will become the red thread of the whole lecture: under and overfitting.

3. Under- and overfitting, from the start

Before writing a single line of code, the deck shows two xkcd strips that frame the two failure modes of every model:

The pedagogical point is deliberately visual: a model can be wrong in two opposite directions, and both are diagnosed by looking at how the model behaves on data it has not seen during training. Chapter 9 will make the same idea quantitative with learning curves; Chapter 10 will add the cross-validation machinery to measure it properly.

4. The disclaimer: understand why the model behaves

The lecturer's disclaimer

Machine learning is not just the application of some algorithms to get the best accuracy. You need to understand why a model is behaving in a certain way — this is very important, especially for the exam! Do not stop at the first (good) result: questioning your algorithm and pipeline is essential. Do not rely on external code without knowing what the code is doing — if you cannot explain your code, the exam is not passed.

This is why the chapters that follow spend as much time on reading models (trees, boundaries, learning curves) as on training them. The exam in this course is oral, and the questions are on all theoretical and practical aspects: being able to narrate why a model draws a given boundary is the skill being tested.

5. Types of machine learning

There are many types of machine learning algorithms, and the deck classifies them in broad categories according to three criteria:

Whether they are trained with human supervision:

  • Supervised — training includes the desired solutions (labels).
  • Unsupervised — training finds structure in unlabeled data.
  • Semi-supervised — a mix: some labeled, most unlabeled.
  • Reinforcement — the agent learns from rewards and punishments.

This course focuses on supervised learning (next section).

Whether they can learn incrementally:

  • Online learning — the model is updated as new data arrives, one chunk (or one instance) at a time.
  • Batch learning — the model is trained on the whole dataset at once and cannot learn incrementally without retraining.

Whether they compare new data to known data points, or detect patterns/models in the training set:

  • Instance-based — the model memorizes examples and generalizes by similarity to them (k-Nearest Neighbors, Chapter 11).
  • Model-based — the model detects a pattern in the training data and builds a mathematical function (decision trees, neural networks).

Keep this taxonomy in mind: Chapter 11 returns to the instance-based vs model-based contrast with k-NN on one side and the perceptron on the other.

6. scikit-learn: the workbench

All the hands-on work of this lecture happens in scikit-learn, the Python machine learning library:

import sklearn as sk
print(sk.__version__)

The version printed in the deck is 1.6.1.

7. The Estimator API

Every scikit-learn algorithm obeys one consistent interface, the Estimator:

The underscore convention is the single most useful detail of the API: you set the hyperparameters before fitting, the model learns the parameters during fitting, and the trailing underscore is scikit-learn's way of telling the two apart.

THE ESTIMATOR LIFECYCLE estimator = Estimator( param1=1, param2=2) you choose the hyperparameters estimator.fit( X_train, y_train) trains on the data estimator.param_ learned parameters end with an underscore the underscore = learned y_pred = estimator .predict(X_test) the same interface for classification, regression, clustering
Plate 8.2 — The lifecycle every estimator follows. Parameters you set appear before the dot; parameters the model learns appear with a trailing underscore; fitting and predicting are always the same two method calls.

Widget — annotated code: the Estimator lifecycle

8. scikit-learn in action

The deck walks the whole pipeline in five lines — choose a model, choose its hyperparameters, fit, predict, evaluate. This is the canonical scikit-learn usage pattern, and every chapter from here on is a variation of it:

Widget — annotated code: the five-step pipeline

Why this pattern matters

Notice the discipline in the five steps: max_depth=2 is a hyperparameter (chosen before fitting), the tree structure learned by fit() is a parameter (learned during fitting), and accuracy_score(y_test, y_pred) evaluates on data the model never saw. This split — choose / fit / evaluate on unseen data — is the backbone of the whole course.

9. Supervised learning: classification and regression

The course focuses on supervised learning tasks: the training includes the desired solutions, i.e. the labels. Within supervised learning, two tasks:

TaskDefinitionExample
ClassificationApproximating a mapping function f from input variables X to discrete output variables y — the function predicts the class or category for a given observation.A spam filter trained with many example emails along with their class (spam or ham).
RegressionApproximating a mapping function f from input variables X to a continuous output variable y — a real value, such as an integer or floating-point value.Predicting the price of a car given a set of features (mileage, age, brand, …).

Everything trained in the next chapters is a classifier — Iris has three classes of flowers — but the same Estimator API works for regression with minimal changes.

10. The data: feature matrix and target array

For a supervised learning problem we need input data along with labels, and we must split the data between test and training set. How? That is the question the deck keeps open and answers in section 13.

scikit-learn uses data in the form of an N-dimensional matrix, split into two objects:

And then the deck asks the crucial question: how do we distinguish target and feature columns? The answer is conceptual, not technical: the target is the column we want to predict — everything else, the columns we are allowed to observe, becomes the features. The choice of what to predict is a modeling decision, made before any code runs.

11. Built-in datasets

scikit-learn ships toy datasets that can be loaded with one call. The deck lists the load_* functions:

import sklearn.datasets as datasets

for dataset in [func for func in dir(datasets) if 'load_' in func]:
    print(dataset)
load_breast_cancer
load_diabetes
load_digits
load_files
load_iris
load_linnerud
load_sample_image
load_sample_images
load_svmlight_file
load_svmlight_files
load_wine

Three of these will appear in this course: load_iris here, and load_wine in the final exercise of the lecture (Chapter 11).

12. The Iris dataset, loaded and profiled

The Iris dataset is the classic benchmark: 150 flowers, 4 measurements, 3 species (setosa, versicolor, virginica). The deck loads it and builds a DataFrame:

from sklearn.datasets import load_iris
import pandas as pd

iris = load_iris()                                        # Load the iris dataset
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)  # DataFrame with the iris data
df['species'] = iris.target                               # Add the species column
# df['species'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)species
05.13.51.40.20
14.93.01.40.20
24.73.21.30.20
34.63.11.50.20
45.03.61.40.20
1456.73.05.22.32
1466.32.55.01.92
1476.53.05.22.02
1486.23.45.42.32
1495.93.05.11.82

Then the deck profiles it — the df.info() output is itself a first data-understanding step:

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
 #   Column             Non-Null Count  Dtype
---  ------             --------------  -----
 0   sepal length (cm)  150 non-null    float64
 1   sepal width (cm)   150 non-null    float64
 2   petal length (cm)  150 non-null    float64
 3   petal width (cm)   150 non-null    float64
 4   species            150 non-null    int64
dtypes: float64(4), int64(1)
memory usage: 6.0 KB

150 rows, 5 columns, no missing values, 4 numeric features and 1 integer label — a clean dataset that lets the lecture focus on modeling rather than cleaning.

Widget — the Iris explorer

Pick a species and read its mean profile. Notice that the two petal features separate the species almost perfectly, while the sepal features overlap — this is exactly what the tree in Chapter 9 will exploit.

13. Splitting into training and test sets

Back to the open question: how do we split? The answer is train_test_split, with a test size and a random seed:

from sklearn.model_selection import train_test_split

X = df.drop("species", axis=1)          # features matrix
y = df["species"]                       # target array
seed = 42                               # Setup random seed. Why?
test_size = 0.2
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=seed)
print(f"X_train: {X_train.shape}")
print(f"y_train: {y_train.shape}")
print(f"X_test:  {X_test.shape}")
print(f"y_test:  {y_test.shape}")
X_train: (120, 4)
y_train: (120,)
X_test:  (30, 4)
y_test:  (30,)

The comment in the code — "Setup random seed. Why?" — is the topic of the next two sections, and the deck will answer it thoroughly. train_test_split randomly shuffles the data before the split is implemented; the random_state parameter controls that shuffle.

TRAIN / TEST SPLIT OF IRIS (150 ROWS) the dataset sepal L sepal W petal L petal W sp 5.1 3.5 1.4 0.2 0 4.9 3.0 1.4 0.2 0 4.7 3.2 1.3 0.2 0 6.7 3.0 5.2 2.3 2 6.3 2.5 5.0 1.9 2 6.5 3.0 5.2 2.0 2 X: (150, 4) · y: (150,) shuffle with seed 42 X_train: (120, 4) y_train: (120,) the model learns here, with its labels 80% of the data X_test: (30, 4) y_test: (30,) evaluation only: the model never sees these labels while training WHY A SEED? same seed → same split others can replicate your results exactly comparing models: the train/test cannot change section 15 expands on this
Plate 8.3 — The split. 150 rows become 120 for training and 30 for testing; features and labels stay aligned in X and y. The seed fixes the shuffle so the split is reproducible — the question the deck itself highlights.

Widget — size the split

Move the test size and read the resulting shapes, exactly as the deck prints them.

14. Randomness, seeds and reproducibility

Why does the code set a seed at all? Because train_test_split shuffles randomly, and randomness is the lack of definite pattern or predictability in information. The deck makes the distinction precise:

The deck's example: when throwing two dice, the outcome of any single roll is unpredictable, but a sum of 7 will tend to occur twice as often as 4. The simulation code rolls a die 100,000 times and two dice 100,000 times, plotting both histograms: the single die is flat, the sum of two dice is triangular, peaking at 7.

RANDOM BUT PREDICTABLE IN FREQUENCY ONE DIE flat: every face ≈ 1/6 1 2 3 4 5 6 TWO DICE (SUM) triangular: 7 is the most frequent sum 23 45 67 89 1011 12 each individual roll is unpredictable — but the shape of 100,000 rolls is a law. Machine learning relies on the same idea: variability per sample, regularity in distribution.
Plate 8.4 — Randomness at the individual level, predictability at the frequency level. This is the gap the pseudorandom seed fills: it lets us freeze the individual rolls so that runs of code become repeatable.

Pseudorandom number generators

A Pseudorandom Number Generator (PRNG) is an algorithm for generating a sequence of numbers whose properties approximate the properties of sequences of random numbers. Two key properties:

print(np.random.randint(1, 7, size=10))
print(np.random.randint(1, 7, size=10))
np.random.seed(42)
print(np.random.randint(1, 7, size=10))
np.random.seed(42)
print(np.random.randint(1, 7, size=10))
np.random.seed(42)
print(np.random.randint(1, 7, size=10))
print(np.random.randint(1, 7, size=10))
[6 6 2 5 4 1 5 1 5 2]
[2 3 1 2 2 6 3 6 5 3]
[4 5 3 5 5 2 3 3 3 5]
[4 5 3 5 5 2 3 3 3 5]
[4 5 3 5 5 2 3 3 3 5]
[4 3 6 5 2 4 6 6 2 4]

Read the output carefully: the two unseeded rolls differ; the three seeded rolls are identical; and the roll after the third seeding differs again, because the generator advanced past the seeded point.

Widget — the dice and the seed

Simulate a seeded PRNG. Roll without a seed and the sequence changes; roll with seed 42 twice and the sequence is identical — exactly the reproducibility the deck demonstrates.

15. Why the random_state matters

Back to train_test_split(..., random_state=seed): the parameter controls the randomness of the shuffle, and that is essential for three reasons:

  1. Reproducibility — by using the same random_state, you can ensure that others can replicate your results exactly.
  2. Consistency in model evaluation — when comparing different models or tuning hyperparameters, the training/test split cannot change: otherwise a difference in accuracy could be caused by a different split, not by the model.
  3. Debugging and testing — during development you might need to debug your code or test different configurations on a stable split.

And the famous question: why 42? The deck answers with the classic reference: The Hitchhiker's Guide to the Galaxy42 is "the answer to the ultimate question of life, the universe, and everything". In code, any integer would work; 42 is the community's joke, and a widely shared convention that makes examples comparable.

For the exam — the four lines that start every model
  1. Define X (feature matrix) and y (target array) — the choice of the target is a modeling decision.
  2. Split with train_test_split(X, y, test_size=..., random_state=...) — the seed makes the split reproducible.
  3. Fit on the training set only: clf.fit(X_train, y_train).
  4. Evaluate on the test set only: accuracy_score(y_test, clf.predict(X_test)) — never on the training set, or you are measuring memory, not learning.

Check your understanding

State Arthur Samuel's and Tom Mitchell's definitions of machine learning.

Samuel (1959): "Machine Learning is the field of study that gives computers the ability to learn without being explicitly programmed." Mitchell (1997): "A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experience E."

What are the three criteria used to classify machine learning algorithms?

(1) Whether they are trained with human supervision — supervised, unsupervised, semi-supervised, reinforcement. (2) Whether they can learn incrementally — online vs batch learning. (3) Whether they compare new data to known data points, or detect patterns/models in the training data — instance-based vs model-based learning. This course focuses on supervised learning.

What is an Estimator in scikit-learn, and what is the underscore convention?

An Estimator is a consistent interface for a wide range of ML applications: an algorithm that learns from the data (fits the data), usable with classification, regression, and clustering. All parameters can be set when creating the estimator and are readable as attributes; every estimator exposes .fit(X_train, y_train) for training and .predict(X_test) for new data. Once fitted, all the estimated parameters become attributes ending with an underscore — e.g. estimator.estimated_param_ — marking what the model learned, as opposed to what you chose.

Distinguish classification and regression, with the deck's examples.

Classification: approximating a mapping function f from inputs X to discrete outputs y, predicting the class or category for a given observation — e.g. a spam filter trained with many example emails along with their class (spam or ham). Regression: approximating f from X to a continuous output y — a real value, such as an integer or floating-point value — e.g. predicting the price of a car given mileage, age, brand, etc.

What are the feature matrix X and the target array y? How do we distinguish target and feature columns?

scikit-learn uses data as an N-dimensional matrix: the feature matrix X (e.g. a Pandas DataFrame) where samples are the individual objects described by the dataset and features describe each sample quantitatively; and the target array y (e.g. a Pandas Series) holding the labels. The distinction is conceptual: the target is the column we want to predict, everything else we are allowed to observe becomes the features — the choice is a modeling decision made before any code runs.

Describe the Iris dataset as loaded and profiled in the deck.

load_iris() gives 150 samples with 4 features (sepal length, sepal width, petal length, petal width, all in cm, float64) and a target with 3 species (0, 1, 2 — setosa, versicolor, virginica, int64). Built as a DataFrame plus a species column it is 150 rows × 5 columns; df.info() shows 150 non-null values in every column, dtypes float64(4) + int64(1), memory usage 6.0 KB. A clean dataset with no missing values.

Write the train_test_split call and the resulting shapes for Iris.

X = df.drop("species", axis=1); y = df["species"]; X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) gives X_train: (120, 4), y_train: (120,), X_test: (30, 4), y_test: (30,). The function randomly shuffles the data before the split is implemented; random_state controls the shuffle.

What is a PRNG, and what role does the seed play?

A Pseudorandom Number Generator is an algorithm for generating a sequence of numbers whose properties approximate the properties of random sequences. The generated sequence is not truly random — it is completely determined by the initial value, called seed. PRNGs matter in practice for their reproducibility: with the same seed, the same sequence is generated — the deck shows three seeded rolls of a die producing identical outputs.

Give the three reasons random_state matters in train_test_split.

Reproducibility: the same random_state lets others replicate your results exactly. Consistency in model evaluation: when comparing models or tuning hyperparameters, the training/test split cannot change, otherwise accuracy differences could come from the split instead of the model. Debugging and testing: a stable split lets you debug code and test configurations reliably. And 42? It is the answer to life, the universe and everything — from The Hitchhiker's Guide to the Galaxy.

What is the lecturer's disclaimer about accuracy?

Machine learning is not just the application of some algorithms to get the best accuracy. You need to understand why a model is behaving in a certain way — especially for the exam. Do not stop at the first (good) result; questioning your algorithm and pipeline is essential. Do not rely on external code without knowing what it does: if you cannot explain your code, the exam is not passed.