This repository is a portfolio project with production-style structure that predicts whether an e-commerce website session is likely to end in a purchase.
It uses the UCI Online Shoppers Purchasing Intention Dataset and wraps a standard classification task in a local-first MLOps workflow: reproducible preprocessing, model training, evaluation, artifact saving, prediction serving, tests, Docker, CI, and lightweight monitoring documentation.
The project is intentionally scoped as a clean portfolio MVP. It is designed to demonstrate reproducibility, testing, API serving, and model lifecycle thinking without adding unnecessary infrastructure.
Public proof record: this repository is also summarized on navidbr.me/work/ecommerce-purchase-intention-mlops as part of Navid's public NAVIDBR Applied AI Systems work record. The site keeps the same boundary: reproducible ML portfolio proof, not deployed commercial use or automated business decisions.
The project trains baseline machine learning models on session-level browsing behavior, selects the best candidate by ROC-AUC, saves the trained pipeline as a local artifact, and exposes predictions through a FastAPI endpoint.
Core workflow:
- Load and validate the dataset.
- Split features from the
Revenuetarget. - Build a preprocessing pipeline for numeric, categorical, and boolean-like fields.
- Train Logistic Regression and Random Forest candidates.
- Evaluate with ROC-AUC, precision, recall, F1-score, and confusion matrix.
- Save the best model and metadata under
artifacts/. - Serve predictions through a local FastAPI app.
Lunera Commerce is a fictional European e-commerce company that wants to understand which visitor sessions show purchase intent.
Purchase intention prediction matters because many commercial actions depend on identifying high-intent or low-intent sessions early enough to act. Examples include funnel diagnostics, campaign analysis, remarketing prioritization, or experimentation around offers and checkout flows.
This repository does not claim to automate those decisions in production. It shows how a university-style data science use case can be structured as a maintainable ML project with clear interfaces, tests, artifacts, and operational thinking.
Dataset: UCI Online Shoppers Purchasing Intention Dataset
Target variable: Revenue
Revenue indicates whether a visitor session resulted in a purchase. The preprocessing code converts boolean or boolean-like string values into binary labels:
1: purchase0: no purchase
The real dataset is not committed to Git. Place it locally at:
data/raw/online_shoppers_intention.csv
A small tracked sample is included at:
data/sample/sample_online_shoppers.csv
The sample data is for tests, examples, and schema demonstration only. It should not be used for model conclusions.
The project keeps the workflow simple and inspectable:
src/data: CSV loading and dataset validationsrc/features: feature/target splitting and scikit-learn preprocessingsrc/models: training, evaluation, artifact loading, and prediction helperssrc/api: FastAPI serving layersrc/monitoring: local drift-report simulationtests: fast pytest coverage using synthetic/sample datareports: model card and monitoring concept notesdocs: portfolio positioning and public-sharing copyartifacts: generated model and metric outputs, excluded from Git except.gitkeep
.
├── README.md
├── CHANGELOG.md
├── requirements.txt
├── Dockerfile
├── Makefile
├── .github/workflows/ci.yml
├── data/
│ ├── README.md
│ └── sample/sample_online_shoppers.csv
├── docs/
│ └── portfolio_positioning.md
├── notebooks/
│ └── .gitkeep
├── src/
│ ├── data/load_data.py
│ ├── features/preprocessing.py
│ ├── models/train.py
│ ├── models/evaluate.py
│ ├── models/generate_report.py
│ ├── models/predict.py
│ ├── api/main.py
│ └── monitoring/drift_report.py
├── tests/
├── reports/
│ ├── model_results.md
│ ├── model_card.md
│ └── monitoring_report.md
└── artifacts/
└── .gitkeep
Create a virtual environment and install dependencies:
python3 -m venv .venv
source .venv/bin/activate
make installEquivalent install command:
python3 -m pip install -r requirements.txtThe Makefile defaults to python3 for macOS/Linux compatibility:
PYTHON ?= python3If your activated virtual environment exposes python and you prefer that command, use:
make test PYTHON=pythonFirst place the real UCI CSV at:
data/raw/online_shoppers_intention.csv
Then run:
make trainEquivalent command:
python3 -m src.models.trainTraining writes generated artifacts to:
artifacts/model.joblib
artifacts/metrics.json
artifacts/model_metadata.json
These files are intentionally ignored by Git. If the raw dataset is missing, the command exits with a clear message explaining where to place it.
After training, evaluate the saved model:
make evaluateEquivalent command:
python3 -m src.models.evaluateThe evaluation script loads artifacts/model.joblib, recreates the deterministic test split, and prints ROC-AUC, precision, recall, F1-score, and the confusion matrix.
Generate the tracked model results report from the saved metrics:
make reportEquivalent command:
python3 -m src.models.generate_reportThe current baseline results are documented in:
reports/model_results.md
These results were generated from the real UCI dataset downloaded locally to data/raw/online_shoppers_intention.csv. The raw dataset and generated model artifacts are intentionally not committed.
Evaluation date: 2026-04-27T17:52:28.949481+00:00
Dataset shape: 12,330 sessions x 18 columns
Target distribution:
| Revenue | Sessions | Share |
|---|---|---|
| False | 10,422 | 84.53% |
| True | 1,908 | 15.47% |
Model comparison:
| Model | ROC-AUC | Precision | Recall | F1-score |
|---|---|---|---|---|
| Logistic Regression | 0.893 | 0.491 | 0.743 | 0.592 |
| Random Forest | 0.916 | 0.761 | 0.474 | 0.584 |
Selected model: random_forest
The Random Forest baseline had the strongest ROC-AUC in this run, and 0.916 is a strong ranking result for this holdout baseline. The default threshold is more conservative: precision is 0.761, but recall is 0.474, so 201 of 382 actual purchasing sessions in the test split were false negatives.
False negatives are missed buyers. False positives are non-purchasing sessions that could receive unnecessary targeting or intervention. A production use case would need threshold tuning based on business costs before any intervention.
Start the local API:
make apiEquivalent command:
python3 -m uvicorn src.api.main:app --reloadHealth check:
curl http://127.0.0.1:8000/healthExpected response:
{
"status": "ok",
"project": "ecommerce-purchase-intention-mlops"
}Example prediction request:
curl -X POST http://127.0.0.1:8000/predict \
-H "Content-Type: application/json" \
-d '{
"Administrative": 1,
"Administrative_Duration": 18.2,
"Informational": 0,
"Informational_Duration": 0.0,
"ProductRelated": 12,
"ProductRelated_Duration": 340.1,
"BounceRates": 0.01,
"ExitRates": 0.03,
"PageValues": 12.3,
"SpecialDay": 0.0,
"Month": "Mar",
"OperatingSystems": 2,
"Browser": 2,
"Region": 3,
"TrafficType": 2,
"VisitorType": "Returning_Visitor",
"Weekend": false
}'Successful prediction responses include this structure. The class, probability, and selected model name depend on the trained artifact:
{
"predicted_class": 1,
"purchase_probability": 0.82,
"model_version": "portfolio-mvp-v1",
"model_metadata": {
"best_model_name": "random_forest",
"target_column": "Revenue"
}
}model_metadata is populated from artifacts/model_metadata.json when that file exists. The real metadata contains additional training details. If the model artifact is missing, /predict returns HTTP 503 with a clear message. /health works whether or not a model has been trained.
Build the API image:
make docker-buildRun the container:
make docker-runEquivalent commands:
docker build -t ecommerce-purchase-intention-mlops .
docker run -p 8000:8000 ecommerce-purchase-intention-mlopsThe container starts the FastAPI application on port 8000. As with local API usage, predictions require a trained model artifact to be available inside the container.
Run the test suite:
make testEquivalent command:
python3 -m pytestThe tests are fast and do not require the real UCI dataset or committed model artifacts. They cover preprocessing, training on synthetic data, prediction with a temporary model artifact, and API behavior.
GitHub Actions runs on push and pull request. The workflow:
- checks out the repository
- sets up Python 3.11
- installs dependencies
- runs
python -m pytest
CI intentionally does not depend on data/raw/ or generated model artifacts.
Included in this MVP:
- reproducible Python package structure
- data validation for the expected target column
- scikit-learn preprocessing and model pipelines
- deterministic train/test split
- baseline model comparison
- tracked baseline model results report
- metric and metadata artifact saving
- reusable prediction helper
- FastAPI serving
- pytest coverage
- Dockerfile for local API packaging
- GitHub Actions CI
- model card
- lightweight monitoring simulation
Not included by design:
- cloud deployment
- Kubernetes
- Terraform
- Airflow
- MLflow or model registry integration
- production alerting or automated retraining
The model card is available at:
reports/model_card.md
It documents the model purpose, intended use, model candidates, evaluation metrics, limitations, business risks, monitoring needs, and future improvements.
Public GitHub descriptions, suggested topics, LinkedIn copy, interview talking points, and resume bullet options are collected in:
docs/portfolio_positioning.md
The monitoring note is available at:
reports/monitoring_report.md
The local monitoring script can compare simple feature distributions between two CSV files:
python3 -m src.monitoring.drift_report \
--reference data/sample/sample_online_shoppers.csv \
--new data/sample/sample_online_shoppers.csvThis writes a JSON report to reports/drift_report.json, which is ignored by Git.
- This is a local-first portfolio MVP, not a full production system.
- The real UCI dataset is excluded from Git and must be added locally.
- The included sample CSV is only for tests and examples.
- The current validation uses a deterministic holdout split, not time-based validation.
- The baseline models are intentionally simple.
- Probability calibration and threshold tuning are not included yet.
- Monitoring is a local simulation and does not include alerts, scheduled jobs, or historical tracking.
- Business impact is not validated with live experiments or intervention outcomes.
Practical next steps:
- add threshold tuning based on business costs
- add probability calibration analysis
- compare models with time-aware validation if timestamped data is available
- add a lightweight experiment tracking option after the MVP is stable
- extend monitoring reports with prediction distribution checks
- document retraining criteria more formally