Skip to content

AI Agents · Guide

Build a Reproducible ML Classifier: A Local Capstone

Run a small scikit-learn project from source through a local prediction API. Inspect delayed-label splits, validation decisions and a held-out report.

Metarix Editorial · Nov 8, 2026 · 6 min read

Share

Documentation-based research

On this page

Complete one small machine learning workflow: define a prediction contract, respect delayed labels, fit a preprocessing pipeline, choose a threshold on validation data, inspect a held-out report, export the model and make a local HTTP prediction.

This is the final project in the Machine Learning Engineer learning path. It uses a real scikit-learn classifier with synthetic data. It is an educational example, not a fault-detection product, production service or measure of your employability.

Download the project and inspect its limits

Get the versioned ML capstone ZIP. It contains source, a synthetic CSV, tests, pinned dependencies, a README and an MIT license. It contains no real customer or equipment data, saved credentials or downloaded pretrained model.

The fixture has 600 independent synthetic hourly observations. Four numeric measurements are available at prediction time: temperature, vibration, load and pressure. A simulated binary target represents a fault in the next shift; the fixture declares its label available eight hours later. The outcomes are sampled from a known feature-based probability formula. They are not observed equipment events.

That declaration makes delayed-label handling visible. It does not validate a real labeling process or prove that this split suits repeating machines, rolling histories or a different forecast horizon. A real project must redesign the data and evaluation contract for its own decision.

Set up the tested environment

We tested Linux with Python 3.12.14, scikit-learn 1.8.0, NumPy 2.3.5 and the remaining dependency pins in requirements.txt. Use Python 3.12 for this project version. From the extracted directory:

sh
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -r requirements.txt
python -m unittest -v

The virtual-environment activation shown is for a POSIX shell. Windows users should use their environment’s activation command. Installing dependencies needs a package index or prepared wheelhouse; after installation, the fixture, training, prediction and tests run without external data or API calls. The tests open an ephemeral localhost port for the HTTP-contract check.

The reviewed project has 13 tests, covering split boundaries, train-only preprocessing, threshold selection, schema validation, deterministic training, JSON-export agreement and HTTP behavior. A passing suite demonstrates these implementation checks, not real-world model quality.

Train once and understand the partitions

sh
python ml_capstone.py train --out artifacts

The command writes model.json and report.json under artifacts. The first 60% of rows are training candidates, the next 20% validation candidates, and the final 20% test rows. Candidates whose labels are unavailable before the next partition starts are removed at the first two boundaries.

Expect 352 training rows, 112 validation rows and 120 test rows; 16 rows are excluded for label availability. Identifier, timestamps and target are not features. Median imputation, scaling and logistic-regression weights are fit on training rows only.

The model family and C=1.0 setting are fixed in advance. Validation F1 chooses a threshold from the fixed 0.1–0.9 grid, with higher thresholds winning ties. The selected model and threshold are frozen before the test report is calculated. Do not tune a new model from that report while continuing to call these rows untouched test data.

Read the result without overstating it

In the tested environment, the shipped fixture selects threshold 0.3. The test partition has 120 rows and 38 positive labels. Its confusion matrix is [[55, 27], [12, 26]], with rows representing true classes and columns predicted classes, ordered 0, 1.

Those counts correspond to 27 false positives and 12 false negatives. Their acceptability depends on an action policy and real decision costs that this fixture does not establish. The purpose is to make a decision tradeoff inspectable, not to advertise industrial accuracy.

The report also includes a prior-probability DummyClassifier. At the displayed threshold 0.5, it predicts every test row negative, so its F1 is zero. This is a disclosed baseline operating point, not a threshold-tuned competitor. Do not present the resulting F1 difference as a general model improvement. Ranking metrics, support and the data-generation limits must also be understood.

Make a prediction and serve it locally

sh
python ml_capstone.py predict --model artifacts/model.json --json '{"temperature_c":75,"vibration_mm_s":5,"load_pct":null,"pressure_kpa":130}'
python ml_capstone.py serve --model artifacts/model.json --port 8765

The first command returns JSON. The second keeps a local server running; use another terminal for:

sh
curl -sS http://127.0.0.1:8765/predict -H 'Content-Type: application/json' -d '{"temperature_c":75,"vibration_mm_s":5,"load_pct":null,"pressure_kpa":130}'

Expect probability, threshold and predicted_class fields. Check that an empty object returns HTTP 400, then explain which part of the input contract it violates. The model permits an individual null measurement and uses the training median, but rejects an entirely missing measurement set.

The server binds only to 127.0.0.1. It is a teaching interface using Python’s HTTPServer, with no production authentication, TLS termination, concurrency design or managed lifecycle. Do not expose it publicly. Public deployment is a separate engineering task.

Explain the exported artifact

The project exports a schema-checked JSON representation of this specific numeric pipeline. It contains feature order, medians, scaling statistics, coefficients, intercept and threshold. Tests compare its prediction with the fitted scikit-learn model. This avoids loading pickle or joblib objects; it is not a general-purpose exporter for arbitrary models.

The report records environment details and hashes for data and model files. Hashes identify bytes when the expected hash is trusted; they do not authenticate an attacker-controlled release. Even a non-executable JSON model can be maliciously altered to change decisions.

What to submit as your portfolio evidence

  • A problem contract naming prediction time, label availability, target and excluded uses.
  • The test output and report from your environment, including versions and class support.
  • An explanation of the two label-availability gaps and train-only transformations.
  • One valid and two invalid local requests, with expected responses.
  • A model card and an operational plan covering monitoring, ownership, privacy and rollback.
  • A proposed next experiment with fresh evaluation data, rather than a redesign selected from this test score.

You have completed this project when you can reproduce and explain the workflow, including its limitations. For specialization, choose a real approved dataset and a relevant role or use case; do not assume that this synthetic score transfers to it.

Sources and test record

Local project checks used Python 3.12.14 and scikit-learn 1.8.0. The project was tested without paid APIs or external datasets. No real fault-detection validation, production hosting, load testing or fairness study was performed.

Share

Keep Reading