Applied Machine Learning — Course Project

Building and Shipping an End-to-End Machine Learning System


Objective

You will take a real problem from a domain you care about (healthcare, finance, education, agriculture, retail, transport, energy, public services…) and carry it through the full industry ML workflow covered in this module:

  • Identify a problem where a real decision changes because of your model.
  • Select and secure a dataset that can actually answer it.
  • Follow the workflow from business understanding through data preparation, feature engineering, modelling, evaluation and error analysis.
  • Track every experiment with a proper tool (MLflow, Aim or Weights & Biases) instead of a notebook full of printed scores.
  • Package and deploy the trained pipeline behind a simple API or interface, and write down how you would monitor it.

Keep it small and finished. A well-framed logistic regression, tracked in MLflow and served by a working FastAPI endpoint, scores higher than an ambitious model that only exists inside a notebook.

What is graded is the reasoning, not the score. An honest AUC of 0.68 with a clear decision and a measured baseline beats a 0.95 produced by a leaked column, every time. If your first model looks excellent, your first job is to find out why.


The Workflow You Will Follow

The project mirrors the module, session by session. Each stage produces something you hand in.

Stage Session Question you must answer What it produces
1. Business understanding 1 What decision changes, who owns it, and what does "success" mean before any modelling? Project charter
2. Data understanding and preparation 2 What is one row? When is each column written? What is missing, and why? Data audit, cleaned dataset, justified split
3. Feature engineering 3 Which features exist at prediction time, and what can be built from them? Feature pipeline in src/
4. Baselines and modelling 1, 4 What do a constant, a rule and a simple model achieve? Does anything beat them? Baseline table, ≥ 2 model families
5. Evaluation 5 Which metric matches the decision? What is the operating point? Metric choice, threshold, cost/capacity reasoning
6. Tuning and error analysis 6 Where is the model wrong, and for whom? Cross-validated tuning, slice analysis
7. Pipelines and experiment tracking 7 Which run produced the final model, with which settings and data? Tracked experiments, registered model
8. Deployment 9 How does someone else get a prediction? Saved artifact + metadata, served model, Dockerfile
9. Monitoring plan 8 How would you know it has stopped working? Monitoring runbook

Session 10 walks through this entire sequence on one dataset. Use it as your template.


Step 1 — Identify the Problem

Start from a decision, not from a dataset or an algorithm. Before choosing data, you must be able to fill in these four lines:

  1. The decision: "At _ (decision point), _ (who) decides whether to ____."
  2. The owner: the person or role whose work changes because of your model.
  3. The action: what they will do differently with a prediction in hand.
  4. The cost of being wrong: what a false positive costs, and what a false negative costs.

If you cannot name the person whose work changes, pick a different problem. "Understanding the drivers of X" is a report, not a decision.

Also ask session 1's question honestly: is this an ML problem at all? If a simple rule, a lookup or a dashboard would do the job, say so — and then either reframe or choose another problem.

Project types

The module covers supervised learning on tabular data in depth, so that is the default.

Type Example problems Your baseline is… You are judged on…
Classification (default) Loan default, patient no-shows, customer churn, crop disease risk, fraud flagging Majority class and an existing or plausible business rule Metric at a chosen operating point (recall at a fixed flag rate, precision@k, PR-AUC), tied to cost or capacity
Regression Delivery time, house price, crop yield, energy demand Mean/median prediction and a simple rule MAE / RMSE in business units, error by slice
Other (with prior approval) Deep learning on images/text, time-series forecasting, recommenders Agreed with your facilitator Agreed with your facilitator

Deep learning is allowed if it beats a well-tuned classical baseline on your data and you can justify its cost. On tabular data of this size it usually will not, and it earns no marks by itself.

Sample project ideas by domain

Domain Problem Decision that changes
Healthcare Predict appointment no-shows Which patients receive a reminder call the day before
Finance Predict SME loan default Which applications go to senior review
Education Predict course dropout risk Which students a counsellor contacts in week 3
Retail / E-commerce Predict customer churn Who receives a retention offer this month
Agriculture Predict crop yield from weather and soil How much fertiliser or storage a cooperative orders
Transport / Logistics Predict late deliveries Which orders get priority dispatch
Energy Predict daily electricity demand How much generation capacity is scheduled
Telecom Predict network complaints by area Where field engineers are sent first
Public services Predict tax or utility payment default Which accounts receive early follow-up

Step 2 — Select a Dataset

Dataset requirements

Requirement Details
Format Tabular (unless an "Other" project has been approved)
Size At least 1,000 rows
Target A column you could genuinely act on, observed after the decision point
Point-in-time Features must be available at the moment the prediction is made
Not allowed The loan book or the student file used in class, or a classic tutorial dataset (Titanic, Iris, MNIST, Boston housing) with names changed. Well-known datasets are acceptable only if you ask a genuinely new question of them
Documented Source, licence, date downloaded and size recorded in your README

Where to find data

General repositories

Source Notes
Kaggle Datasets Widest catalogue. Always check the Licence tab, and be suspicious of datasets with suspiciously perfect scores in their notebooks
UCI Machine Learning Repository Small, clean tabular datasets with documentation
OpenML Curated tabular datasets with task definitions and benchmark results
Google Dataset Search Search engine across thousands of data portals
Hugging Face Datasets Text, image, audio and a growing set of tabular data
Awesome Public Datasets Large list grouped by domain

Domain-specific

Domain Sources
Health WHO Global Health Observatory, CDC Data, PhysioNet (registration required)
Finance & Economics World Bank Open Data, IMF Data, yfinance
Education PISA, UCI Student Performance
Climate & Agriculture NASA Earthdata, FAOSTAT, Open-Meteo API
Sports football-data.co.uk, ESPNcricinfo Statsguru

Nepal and regional data

Source Notes
Open Data Nepal Education, health, demographics, local government
data.gov.np Government open data portal
National Statistics Office Census and national survey data
Nepal Rastra Bank Macroeconomic and banking statistics
Humanitarian Data Exchange Health, infrastructure and humanitarian data

Workplace or self-collected data is encouraged — it usually produces the most interesting projects. Workplace data requires written permission and must be anonymised; never commit personal data to a public repository. If you scrape, respect robots.txt and the site's terms of service, and rate-limit your requests.

Three data rules

  1. Check the licence and cite the source. If it forbids redistribution, link to it instead of committing the file.
  2. Freeze your data. Download once, record its MD5 hash, and work from that copy. If you pull from an API, cache the response to CSV. A dataset that changes underneath you makes every number in your report irreproducible.
  3. Keep the repository small. Commit files under ~50 MB. For anything larger, put download instructions in data/README.md and git-ignore data/raw/. (DVC is a welcome optional extra.)

Step 3 — Write the Project Charter (Business Understanding)

Before touching a model, write session 1's one-page charter. Every later stage refers back to it: choosing a metric fills in a charter field; detecting drift tests a charter assumption.

Field What it must say
Business problem What is going wrong today, in the business's own words and numbers
Decision changed The decision, the decision point, and the possible actions
Decision owner The role accountable for that decision
ML task Classification / regression, and what exactly is predicted
Target The column, and over what window it is observed
Unit of prediction What one row is, and when it is scored
Baseline to beat The existing rule or practice, measured — not assumed
Offline criterion A metric with a number, e.g. "recall ≥ 0.60 while flagging ≤ 25% of cases"
Business criterion The outcome in business units (rupees, hours, patients reached)
Guardrails What must not get worse: latency, fairness across groups, explainability, no protected attributes
Kill criteria The conditions under which you would stop or recommend against deployment
Known risks Leakage suspects, shifting conditions, data quality concerns

Success and kill criteria are written before modelling and are not changed afterwards to fit the result. If you change them, say so and say why.


Step 4 — Data Understanding, Preparation and Features

  • Point-in-time audit of every column: when is it written, relative to the decision point? Drop anything written afterwards. Be especially suspicious of status, final_, resolution_, closed_ and any single column that is suspiciously predictive.
  • Missingness: understand why values are missing before filling them. Missingness itself is often a feature.
  • Distributions, outliers, duplicates, class balance — with written insights, not just plots.
  • A justified split: random, stratified, grouped or time-based — and why that one matches how the model will be used.
  • All preprocessing inside a scikit-learn Pipeline / ColumnTransformer, fitted only on training data. If preprocessing is fitted before the split, the evaluation is invalid.
  • Engineered features built from information available at prediction time, implemented in src/ so training and serving use the same code.

Step 5 — Baselines, Modelling and Evaluation

Baselines first. You must report them, and you must try to beat them. At minimum:

  1. A constant (majority class or mean).
  2. A rule (the existing business practice, or the most obvious one-line heuristic).
  3. A simple model (logistic or linear regression on a few obvious features).

Then:

  • Compare at least two model families (e.g. regularised linear model vs. gradient boosting / random forest) with cross-validation, reporting the spread across folds, not just the mean.
  • Tune hyperparameters inside cross-validation (GridSearchCV, RandomizedSearchCV or Optuna).
  • Choose the metric for the decision. Accuracy on imbalanced data is not acceptable. For classification, pick an operating point (threshold) using cost or capacity — e.g. "the team can call 200 patients a day".
  • Touch the held-out test set once, at the end.
  • Error analysis by slice: where is the model wrong, and for whom? Check performance across meaningful groups (region, gender, age band, product type…) for both accuracy and fairness.
  • Optional but valued: explainability (permutation importance, SHAP) and probability calibration.

Step 6 — Experiment Tracking

Every training run that appears in your report must be logged in an experiment tracker. "It's somewhere in the notebook" is not acceptable.

Tool Notes
MLflow (recommended) Used in session 7. Runs entirely locally with a SQLite backend; includes a model registry
Aim Open-source, local, fast UI for comparing many runs
Weights & Biases Hosted, free for students; easy sharing of dashboards

Minimum requirements for every run:

Log Examples
Parameters Model family, hyperparameters, feature set, threshold, random seed, split strategy
Metrics CV mean and standard deviation, test metric(s), metric at the operating point, baseline scores
Artifacts The fitted pipeline, confusion matrix / residual plot, feature importance, the metadata JSON
Lineage Data file hash (MD5) and git commit hash

Also required:

  • Baselines logged as runs too, so the comparison lives in the tracker.
  • The final model registered or tagged (e.g. MLflow Model Registry, or a final tag) so it can be reloaded by run ID.
  • Screenshots of the run comparison view in your report.
import mlflow

mlflow.set_tracking_uri("sqlite:///mlflow.db")
mlflow.set_experiment("my-project")

with mlflow.start_run(run_name="gradient-boosting-v2"):
    mlflow.log_params({"model": "HistGradientBoosting", "learning_rate": 0.05, "seed": 42})
    mlflow.log_metrics({"cv_pr_auc_mean": 0.41, "cv_pr_auc_std": 0.02})
    mlflow.sklearn.log_model(pipeline, "model")

Step 7 — Packaging and Basic Deployment

The artifact

Save the entire pipeline (preprocessing + model) with joblib, plus a metadata JSON beside it, as in session 9: model name and version, training date, number of training rows, data hash, feature lists, threshold, library versions and a one-line description of what the prediction means. Always check the round trip: a reloaded model must give the same predictions.

The served model (required)

Build one of the following that loads the saved artifact once at startup:

Option What it must do
FastAPI endpoint POST /predict with a Pydantic-validated input schema; returns prediction, probability (classification) and model version. A GET /health endpoint. Rejects invalid input with a clear error
Streamlit / Gradio interface Form for the inputs; shows the prediction, its probability and the recommended action in plain words

Doing both (Streamlit calling your FastAPI) is welcome but not required.

One rule that matters: never copy preprocessing code from a notebook into the app. Import it from src/, or load it inside the saved pipeline. Otherwise the two drift apart and the app predicts nonsense.

Containerisation (required)

A Dockerfile that builds and runs your service from a clean clone. docker-compose.yml is recommended if you run more than one service (e.g. API + UI, or API + MLflow).

Public deployment (bonus)

Deploy to a free host and put the URL in your README — e.g. Hugging Face Spaces, Streamlit Community Cloud, Render or Railway.


Step 8 — Monitoring Plan

Half a page, in the format of session 8's runbook. Labels usually arrive late, so monitor inputs as well as outcomes.

Check Frequency Alarm Action Owner
API errors, latency Continuous e.g. error rate > 1%, p95 > 2 s … …
Schema and null rates Daily New null pattern or category … …
PSI on top features Weekly Any feature > 0.25 … …
Prediction / flag rate Weekly ±30% vs. trailing period … …
Realised performance As labels mature Below charter criterion Recalibrate, retrain or roll back …

State when you would retrain, and what would make you roll back.


Core Requirements

Requirement Details
Team size Individual
Language Python. scikit-learn is sufficient
Workflow All stages above, each with its deliverable
Experiment tracking MLflow, Aim or W&B — every reported result traceable to a run
Code structure Organised repository (below), not one long notebook
Serving FastAPI endpoint or Streamlit/Gradio interface loading the saved artifact
Containerisation Dockerfile that runs from a clean clone
Reproducibility Pinned requirements.txt, fixed seeds, python src/train.py runs end to end
Version control Git repository with regular, meaningful commits — not one commit at the end

Project Structure

your-project/
├── README.md                 # recommendation, problem, data, results, how to run
├── CHARTER.md                # the one-page project charter
├── MONITORING.md             # the monitoring runbook
├── requirements.txt          # pinned versions
├── Dockerfile
├── docker-compose.yml        # recommended
├── data/
│   ├── README.md             # source, licence, download date, MD5 hash
│   ├── raw/                  # original data (git-ignored if large)
│   └── processed/            # cleaned data used for training
├── notebooks/
│   ├── 01_data_audit_eda.ipynb
│   ├── 02_baselines_modelling.ipynb
│   └── 03_evaluation_error_analysis.ipynb
├── src/
│   ├── config.py             # paths, seeds, feature lists, threshold
│   ├── data.py               # loading, cleaning, splitting
│   ├── features.py           # preprocessing + feature pipeline
│   ├── train.py              # trains, logs to the tracker, saves the artifact
│   ├── evaluate.py           # test-set and slice evaluation
│   └── predict.py            # loads the artifact and predicts
├── models/
│   ├── model.joblib          # the full pipeline
│   └── model.json            # metadata
├── app/
│   ├── api.py                # FastAPI service
│   └── ui.py                 # Streamlit / Gradio (if used)
└── tests/                    # optional: pytest for features and the API

Notebooks are for exploring and explaining; src/ holds everything the app depends on. Add mlruns/, mlflow.db, .aim/ and wandb/ to .gitignore.

You may use a standard template instead — say which in your README: Cookiecutter Data Science, Kedro, or your own layout, as long as it separates data, exploration, source code, models and the app.


What to Submit

Submit a single GitHub repository link containing:

# Deliverable Notes
1 Project charter CHARTER.md, one page
2 Notebooks Data audit, modelling and evaluation — narrated, and they run top to bottom after a kernel restart
3 Source code src/ with a reproducible train.py
4 Experiment tracking evidence Tracker screenshots in the report; run ID of the final model in the README (W&B: a public project link)
5 Model artifact Saved pipeline + metadata JSON
6 Served model FastAPI or Streamlit/Gradio, with a Dockerfile
7 Monitoring plan MONITORING.md, half a page
8 README The recommendation in one paragraph at the top, then how to install, train, track and run — reproducible in under ten minutes
9 Final report 4–6 pages, PDF, structure below
10 Slides For a 10-minute presentation with a live demo

Final Report Structure (4–6 pages)

  1. Recommendation — one paragraph, in words a head of department would use: deploy, do not deploy, or what it would take.
  2. Problem and charter — the decision, its owner, success and kill criteria.
  3. Data — source, licence, size, point-in-time audit, leakage checks, split choice.
  4. Preparation and features — key insights and the decisions you made, with reasons.
  5. Modelling — baselines, models compared, tuning, with fold spread.
  6. Evaluation and error analysis — metric at the operating point, cost/capacity reasoning, slices where the model fails.
  7. Experiment tracking — how runs were organised, screenshots, how to recover the final model.
  8. Deployment — architecture, how to run it, screenshots or sample request/response.
  9. Monitoring — summary of the runbook.
  10. Limitations, ethics and next steps — what you would do with more time or data; who could be harmed by errors; note any use of AI assistants and how.

Evaluation Criteria

Component Weight What a strong submission shows
Problem framing and dataset 15% A named decision, owner and decision point. Success and kill criteria written before modelling. Suitable, documented, frozen dataset
Data discipline and features 20% Point-in-time audit of every column. Missingness understood, not just filled. Split justified. No leakage — and evidence you went looking. Features in a pipeline
Modelling and evaluation 20% Measured baselines beaten (or honestly not). ≥ 2 model families with cross-validation and fold spread. Metric matched to the decision, operating point chosen, error analysis by slice
Experiment tracking and reproducibility 15% Every reported result traceable to a tracked run with params, metrics, artifacts, data hash and commit. Final model registered. train.py runs from a clean clone with pinned dependencies
Deployment and monitoring 15% Saved pipeline with metadata, served via API or UI with input validation, Dockerised, runs from a clean clone. A concrete, owned monitoring runbook
Communication and honesty 15% Clear recommendation up front, complete report, 10-minute presentation with a working live demo, honest limitations
Total 100%

Bonus (up to 5%): a public deployment URL; unit tests (pytest) for features and the API; a CI workflow (GitHub Actions) that runs tests and builds the Docker image; model explainability in the app; data versioning with DVC; a drift report (e.g. Evidently) on a simulated "future" slice of your data.


Common Ways Projects Lose Marks

  • No named decision. The single biggest one.
  • No baseline, or a baseline that is assumed rather than measured.
  • A leaked column — and a celebrated score that came from it.
  • Accuracy on imbalanced data.
  • Preprocessing fitted before the split. Use a pipeline and it cannot happen.
  • Results in the report that cannot be found in the tracker.
  • An app that re-implements preprocessing instead of loading the pipeline.
  • "Works on my machine" — the Docker image or requirements.txt fails from a clean clone.
  • A notebook that does not run after restarting the kernel.
  • Burying the recommendation at the end of the report.

Purpose Recommended
Data handling pandas, numpy
Visualisation matplotlib, seaborn
Modelling scikit-learn (optionally XGBoost / LightGBM, Optuna)
Explainability permutation importance, SHAP
Experiment tracking MLflow (recommended), Aim, Weights & Biases
Model saving joblib + metadata JSON
Serving FastAPI + Uvicorn, Streamlit, Gradio
Containerisation Docker, Docker Compose
Testing / CI (bonus) pytest, GitHub Actions
Monitoring (bonus) Evidently, or PSI computed by hand as in session 8
Version control Git, GitHub

Getting Started

# Repository and environment
git init my-project && cd my-project
python -m venv .venv && source .venv/bin/activate
pip install pandas numpy scikit-learn matplotlib seaborn joblib mlflow fastapi uvicorn streamlit
pip freeze > requirements.txt

# Train and log runs
python src/train.py
mlflow ui --backend-store-uri sqlite:///mlflow.db     # open http://127.0.0.1:5000

# Serve the model
uvicorn app.api:app --reload                          # open http://127.0.0.1:8000/docs
streamlit run app/ui.py                               # open http://localhost:8501

# Containerised
docker compose up --build

Frequently Asked

My model is barely better than the baseline. Then that is your finding. Report it clearly, show what you tried, and say what data would change the answer. This is a pass-worthy and often excellent project.

Do I have to use MLflow? No — Aim or Weights & Biases are equally acceptable. What is required is that every reported number is traceable to a logged run.

Does "deployment" mean it has to be public? No. A Dockerised service that runs locally from a clean clone meets the requirement. A public URL is a bonus.

How long should the notebook be? Long enough to follow the reasoning, short enough that someone reads it all. Session 10's Part A is about the right length.


Academic Integrity

You may use libraries, documentation and AI tools as references, but you must be able to explain every line of your code and every modelling decision in the presentation. Cite your data sources, and state in your report whether you used an AI assistant and how.