A 3-class classifier (Low / Moderate / High burnout risk) trained on synthetic employee behavioral data, with a Streamlit dashboard for interactive predictions.
Given 18 daily behavioral signals (meeting load, sleep, after-hours work, mood, etc.), the model predicts a burnout risk category and the probability for each class. The dashboard is a thin UI layer over a scikit-learn pipeline that is trained and evaluated by a separate, reproducible script.
The dataset is entirely synthetic. It is not real employee data.
There is no legitimate public dataset combining per-employee behavioral signals with a burnout label — real data like this is either private, restricted by employment/privacy law, or doesn't exist in usable form. Rather than pretend otherwise, this project generates its own data and documents exactly how.
- Source:
data/generate_synthetic_data.py, seed=42, 4,000 rows - Features (18): meeting load (count, minutes, back-to-back count, gap between meetings), focus time (deep work minutes, context switches, interruptions), after-hours activity (emails, work minutes), recovery (sleep hours, exercise minutes, mood rating, caffeine), task load (completed, overdue), and context (WFH flag, commute minutes, sick/caregiving flag)
- Label generation: each feature is z-scored and combined using fixed,
documented weights (see
STRAIN_WEIGHTSin the generator script) into a latent "strain score," plus Gaussian noise. The score is then binned into Low / Moderate / High using quantile thresholds. This is a synthetic proxy built for this project — it is not a reproduction of any published psychological burnout instrument (e.g. the Maslach Burnout Inventory). - Class balance: Low 40% / Moderate 35% / High 25%
- Reproducibility: deterministic given the fixed seed; re-running the script produces an identical dataset
- Stratified 80/20 train/test split (
src/data_loader.py) - Standardization via
StandardScaler(fit on train only) - Two baselines are trained for comparison:
- Majority-class dummy classifier (accuracy floor)
- Logistic Regression
- One additional candidate: Random Forest (200 trees, max depth 10)
- Each real model (not the dummy) is evaluated with 5-fold stratified cross-validation on the training set
- The "final model" is not hardcoded.
src/train.pyselects whichever of Logistic Regression / Random Forest has the higher mean CV accuracy, and that's what gets saved and used by the app - Final reported numbers come from the untouched 20% test set
Numbers below are from reports/metrics.json, generated by src/train.py,
seed=42. Full confusion matrices and per-class metrics are in that file.
| Model | Test accuracy | 5-fold CV accuracy |
|---|---|---|
| Dummy (majority class) | 40.0% | — |
| Logistic Regression | 72.8% | 74.4% ± 1.8% |
| Random Forest | 62.6% | 63.0% ± 1.5% |
Selected model: Logistic Regression (72.8% test accuracy). Random Forest scored lower here this is genuine, not a mistake: the synthetic labels are generated as a linear combination of features plus noise (see Data section above), so a linear model has a natural advantage on this particular dataset. This should not be read as "logistic regression beats random forests" in general it's a property of how this specific synthetic data was built.
Logistic Regression confusion matrix (test set, rows=true, cols=predicted):
| Predicted Low | Predicted Moderate | Predicted High | |
|---|---|---|---|
| True Low | 262 | 58 | 0 |
| True Moderate | 61 | 182 | 37 |
| True High | 2 | 60 | 138 |
Per-class precision / recall / F1 (Logistic Regression, test set):
| Class | Precision | Recall | F1 | Support |
|---|---|---|---|---|
| Low | 0.806 | 0.819 | 0.812 | 320 |
| Moderate | 0.607 | 0.650 | 0.628 | 280 |
| High | 0.789 | 0.690 | 0.736 | 200 |
The model separates Low and High risk reasonably well; Moderate is the hardest class to call, which is expected it's the middle bucket with the least distinct signal.
git clone https://github.com/SSVP-debug/Burnout-prediction.git
cd Burnout-prediction
pip install -r requirements.txt
# Regenerate the dataset (deterministic, seed=42)
python data/generate_synthetic_data.py
# Train, cross-validate, evaluate, and write reports/metrics.json
python -m src.train
# Or step through everything in a notebook:
jupyter notebook notebooks/model_evaluation.ipynbreports/metrics.json is checked into the repo, so you can diff your locally
reproduced run against it directly the numbers should match exactly given
the fixed seed.
pip install -r requirements.txt
python data/generate_synthetic_data.py # if data/burnout_data.csv doesn't exist
python -m src.train # if models/ doesn't exist yet
streamlit run app.pyIf models/burnout_model.joblib doesn't exist, app.py will train it
automatically on first run (this takes a few seconds).
burnout-prediction/
├── data/
│ └── generate_synthetic_data.py # synthetic dataset generator (documented)
├── src/
│ ├── data_loader.py # load + stratified split
│ ├── preprocessing.py # shared StandardScaler
│ ├── train.py # baselines, CV, model selection, metrics export
│ └── evaluate.py # confusion matrix + precision/recall/F1
├── notebooks/
│ └── model_evaluation.ipynb # reproduces reported metrics end-to-end
├── tests/
│ └── test_preprocessing.py # data generation + preprocessing sanity tests
├── reports/
│ └── metrics.json # full evaluation results (checked in as evidence)
├── models/ # gitignored — regenerate via `python -m src.train`
└── app.py # Streamlit dashboard
python -m pytest tests/ -v- Synthetic data. This does not reflect real employee populations, real organizational dynamics, or any validated burnout instrument. It should not be used to make real decisions about real people.
- Small, single-source sample. 4,000 synthetic rows from one generation process — no diversity of underlying data-generating assumptions.
- Label leakage by construction. Because the labels are a direct (noisy) function of the features by design, accuracy here is not comparable to accuracy on a real-world burnout prediction task, where the relationship between behavioral signals and actual burnout is far noisier and less linear.
- No temporal structure. Each row is an independent day-snapshot; the model doesn't see trends over time, which is arguably more relevant to real burnout than a single day's numbers.
- Moderate class is the weak point. Precision/recall for "Moderate" is noticeably lower than for "Low" or "High" see the confusion matrix above.
This is a portfolio project demonstrating an ML workflow (data generation, baseline comparison, cross-validation, evaluation, reproducibility), not a production-ready or clinically validated tool.
MIT