Module 1 · Why Machine Learning Still Needs You ⏱ 18 min

The Real ML Workflow

By the end of this lesson you will be able to:
  • List the stages of a real ML project from problem definition to monitoring
  • Explain why data quality and problem framing matter more than model choice
  • Recognise data leakage and the train-test boundary

Machine learning courses spend most of their time on algorithms, but in a real job the model is the smallest part of the project. A typical team spends far more effort understanding the problem, cleaning data, engineering features, and fighting bugs in deployment than it ever spends choosing between random forests and gradient boosters. The difference between a project that ships and one that dies in a notebook is usually the workflow, not the math. This lesson walks the full loop — problem, data, features, model, evaluation, deployment, and monitoring — so you can see where the real risks hide and why modelling is only the middle act. If you learn nothing else from this course, learn that a perfect algorithm on the wrong problem is still wrong.

flowchart LR
  P["Problem"] --> D["Data"]
  D --> F["Features"]
  F --> M["Model"]
  M --> E["Evaluate"]
  E --> De["Deploy"]
  De --> Mo["Monitor"]
  Mo --> P
  style P fill:#b45309,color:#fff
  style M fill:#166534,color:#fff
  style Mo fill:#7c3aed,color:#fff
The full ML workflow: a loop, not a straight line.

Problem and data: the foundation

Every project starts with a question that is fuzzier than it looks. Predicting customer churn sounds simple until you define what churn means — is it no purchase for 30 days, or cancellation, or a refund? The definition decides which data you collect and whether the model even answers the business question. Once the problem is sharp, you gather raw data and perform exploratory data analysis (EDA): plotting distributions, counting missing values, and looking for impossible entries like negative ages or dates in the future. A model can only learn what the data contains, and dirty data teaches dirty lessons. Many experienced practitioners say that 80 percent of project time is data work, and they are not exaggerating.

A tiny data-quality report: count missing values, invalid entries, and duplicates.
def data_quality_report(records):
    total = len(records)
    missing_age = sum(1 for r in records if r.get('age') is None)
    invalid_age = sum(1 for r in records if r.get('age') is not None and r['age'] < 0)
    duplicates = len(records) - len({tuple(sorted(r.items())) for r in records})
    print(f"Total records: {total}")
    print(f"Missing age: {missing_age}")
    print(f"Invalid age: {invalid_age}")
    print(f"Duplicates: {duplicates}")

data_quality_report([
    {'age': 25, 'spent': 100},
    {'age': None, 'spent': 50},
    {'age': -3, 'spent': 200},
    {'age': 25, 'spent': 100},
])

Features and model: where the math lives

Feature engineering is the art of turning raw data into numbers the model can actually use. A timestamp becomes hour-of-day and day-of-week. A free-text review becomes a bag of word counts. Geographic coordinates become distance from the nearest store. The best features are the ones that capture the underlying cause of the pattern you are trying to predict. After features come the model and training loop — the part every course emphasizes. You split data into training and validation sets, pick an algorithm, and run the optimizer. But remember: a sophisticated model on weak features will almost always lose to a simple model on strong features. The model is important, but it is not a substitute for understanding your data.

flowchart TD
  Train["Training set<br/>learn the pattern"] --> Model["Model"]
  Test["Test set<br/>never seen during training"] --> Model
  Model -->|"predict"| Test
  Test -->|"compare"| Score["Score"]
  style Train fill:#166534,color:#fff
  style Test fill:#b45309,color:#fff
  style Score fill:#7c3aed,color:#fff
The train-test split: the test set must remain untouched until final evaluation.
A deterministic train-test split using a fixed random seed.
import random
random.seed(0)

def train_test_split(data, train_fraction=0.8):
    shuffled = list(data)
    random.shuffle(shuffled)
    split = int(len(shuffled) * train_fraction)
    return shuffled[:split], shuffled[split:]

train, test = train_test_split(list(range(10)))
print("train:", train)
print("test:", test)

Evaluation, deployment, and monitoring: the long tail

Evaluation means measuring the model on data it has never seen, using metrics that match the business goal. Accuracy is the famous one, but it can hide disasters when the classes are imbalanced — a fraud detector that always predicts not fraud is 99 percent accurate and completely useless. Deployment turns the model from a notebook into a system that serves predictions to real users. That means building an API, handling latency, versioning the model, and planning for rollback when it breaks. Monitoring watches the model after launch, because the world changes. A recommendation system trained on summer vacation data will suggest beach gear in December unless you detect that the input distribution has shifted — a problem called concept drift. The loop never ends; it only slows down.

Accuracy and a simple concept-drift detector, built from scratch.
def accuracy(predictions, labels):
    correct = sum(1 for p, l in zip(predictions, labels) if p == l)
    return correct / len(labels)

def concept_drift_warning(old_counts, new_counts, threshold=0.1):
    total_old = sum(old_counts.values())
    total_new = sum(new_counts.values())
    for category in old_counts:
        p_old = old_counts[category] / total_old
        p_new = new_counts.get(category, 0) / total_new
        if abs(p_old - p_new) > threshold:
            return True
    return False

print("Accuracy:", accuracy([1, 0, 1, 1], [1, 0, 0, 1]))
print("Drift?", concept_drift_warning(
    {'A': 80, 'B': 20},
    {'A': 50, 'B': 50},
))
flowchart LR
  Deploy["Deployed model"] -->|"serves predictions"| Users["Users"]
  Users -->|"generate new data"| Data["Data pipeline"]
  Data -->|"feeds back"| Deploy
  Data -->|"drift detected?"| Alert["Alert engineer"]
  style Deploy fill:#166534,color:#fff
  style Alert fill:#b91c1c,color:#fff
Deployment creates a feedback loop: user behaviour generates new data, which may trigger retraining.
Exercise

What does this simple train-test split print?

def train_test_split(data):
    mid = len(data) // 2
    return data[:mid], data[mid:]

train, test = train_test_split([10, 20, 30, 40])
print(train)
print(test)
Exercise

Write accuracy(predictions, labels) that returns the fraction of correct predictions. Both arguments are equal-length lists.

def accuracy(predictions, labels):
    # fraction of matching elements
    pass
Exercise

This train_model function accidentally leaks test data into training by using the combined dataset to compute a mean. Fix it so only train_data is used to compute the mean.

def train_model(train_data, test_data):
    combined = train_data + test_data
    mean = sum(combined) / len(combined)
    adjusted = [x - mean for x in train_data]
    return adjusted
Exercise

Write feature_engineer(records) that takes a list of dicts with keys 'width' and 'height', and returns a new list of dicts that also includes 'area' (width * height) and 'is_square' (True if width == height). Do not modify the original dicts.

def feature_engineer(records):
    # Return new list with 'area' and 'is_square' added
    pass
Exercise

Write workflow_stage(description) that returns the ML workflow stage described: 'problem', 'data', 'features', 'model', 'evaluation', 'deployment', or 'monitoring'. Use these keywords: 'label' or 'define' -> 'problem'; 'missing' or 'clean' -> 'data'; 'area' or 'engineer' -> 'features'; 'train' or 'fit' -> 'model'; 'accuracy' or 'score' -> 'evaluation'; 'serve' or 'API' -> 'deployment'; 'drift' or 'degrade' -> 'monitoring'. Otherwise return 'unknown'.

def workflow_stage(description):
    # Map description keywords to workflow stages
    pass

The loop is never linear

In textbooks the workflow is drawn as a straight line, but in practice you bounce backwards constantly. Evaluation reveals that your features are weak, so you return to feature engineering. Deployment shows the model is too slow, so you simplify it and retrain. Monitoring detects drift, so you collect fresh data and start again. Each iteration teaches you something about the problem that you could not have known at the start. The teams that succeed are not the ones with the best initial plan; they are the ones that build feedback loops fast enough to discover their mistakes before the project runs out of budget.

Recap

  • The ML workflow is a loop: problem -> data -> features -> model -> evaluation -> deployment -> monitoring.
  • Problem framing and data quality consume more time and determine more success than model choice.
  • Feature engineering turns raw data into informative numbers; strong features beat fancy models.
  • Data leakage — letting test information into training — produces inflated scores that collapse in production. Split early and touch the test set once.
  • Monitoring catches concept drift after deployment, because the real world changes while your model stays frozen.
  • Modelling is the middle act. The beginning and the end decide whether the project lives or dies.

Checkpoint quiz

You fill missing values using the mean of the ENTIRE dataset before splitting into train and test. What is the risk?

A recommendation system trained in June starts suggesting beach gear in December. Which workflow stage addresses this?

Go deeper — technical resources