Lesson 14
ML Workflow
Structure an end-to-end machine learning project from problem definition through data exploration, feature engineering, model selection, evaluation, and iteration.
A machine learning project is not a single fit and predict. It is a loop: you define the problem, understand the data, engineer features, train and evaluate a baseline, diagnose errors, improve, and repeat. Structure prevents wasted effort.
Step 1: define the problem
Before writing code, answer:
- What decision or action will the prediction support?
- Is it regression, classification, or clustering?
- What metric matters? (Accuracy? Recall? RMSE?)
- What is the baseline? (A simple rule? Historical average?)
A clear problem definition stops you from optimising the wrong thing.
Step 2: explore and prepare the data
import numpy as np
import pandas as pd
from numpy.random import default_rng
rng = default_rng(42)
n = 300
experience = rng.integers(1, 21, n)
certifications = rng.integers(0, 7, n)
overtime = rng.integers(0, 45, n)
education = rng.choice([10, 12, 14, 16, 18], n, p=[0.05, 0.25, 0.35, 0.25, 0.10])
noise = rng.normal(0, 4500, n)
salary = (20000 + experience * 3200 + (education - 10) * 1500 +
certifications * 1200 + overtime * 80 + noise).round(-2)
salary = np.clip(salary, 18000, 160000).astype(int)
senior = (salary >= 65650).astype(int)
top = ((experience >= 15) & (certifications >= 5)).astype(int)
employees = pd.DataFrame(dict(
experience=experience, certifications=certifications,
overtime=overtime, education=education, salary=salary,
senior=senior, top=top,
))
# Quick data exploration
print(employees.shape)
print(employees.dtypes)
print(employees[["experience", "certifications", "salary"]].describe().round(1))
print("\nclass balance:", employees["senior"].value_counts().to_dict())Output:
(300, 7)
experience int64
certifications int64
overtime int64
education int64
salary int64
senior int64
top int64
dtype: object
experience certifications salary
count 300.0 300.0 300.0
mean 10.5 3.0 65239.0
std 5.5 2.1 18735.0
min 1.0 0.0 24000.0
25% 6.0 1.0 51375.0
50% 10.0 3.0 65650.0
75% 15.0 5.0 81000.0
max 20.0 6.0 104900.0
class balance: {0: 150, 1: 150}Step 3: baseline → improve → evaluate
import numpy as np
import pandas as pd
from numpy.random import default_rng
rng = default_rng(42)
n = 300
experience = rng.integers(1, 21, n)
certifications = rng.integers(0, 7, n)
overtime = rng.integers(0, 45, n)
education = rng.choice([10, 12, 14, 16, 18], n, p=[0.05, 0.25, 0.35, 0.25, 0.10])
noise = rng.normal(0, 4500, n)
salary = (20000 + experience * 3200 + (education - 10) * 1500 +
certifications * 1200 + overtime * 80 + noise).round(-2)
salary = np.clip(salary, 18000, 160000).astype(int)
senior = (salary >= 65650).astype(int)
top = ((experience >= 15) & (certifications >= 5)).astype(int)
employees = pd.DataFrame(dict(
experience=experience, certifications=certifications,
overtime=overtime, education=education, salary=salary,
senior=senior, top=top,
))
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
X = employees[["experience", "certifications", "overtime", "education"]].values
y = employees["senior"].values
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
baseline = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
baseline.fit(X_train, y_train)
improved = GradientBoostingClassifier(n_estimators=100, random_state=0).fit(X_train, y_train)
print(f"baseline: {baseline.score(X_test, y_test):.3f}")
print(f"improved: {improved.score(X_test, y_test):.3f}")Output:
baseline: 0.933
improved: 0.883Always establish a baseline first. It tells you whether a complex model is worth the extra effort.
Step 4: iterate on errors
Look at the rows your model got wrong. Common fixes:
- Missing important features → add them.
- Class imbalance → adjust class weights.
- Overfitting → add regularisation or more data.
- Underfitting → use a more complex model or engineer features.
Track each experiment. Reproducibility requires fixed random seeds and the same train-test split.
Key takeaways
- Define the problem and metric before writing any code
- Explore data shapes, types, and class balance early
- Train a simple baseline before trying complex models
- Iterate: diagnose errors, improve features or model, re-evaluate
- Track experiments with fixed seeds and identical splits
Loading playground…
Check your understanding
ML Workflow Quiz
What is the first step in an ML workflow?
1 / 10