Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Burnout Risk Predictor

A 3-class classifier (Low / Moderate / High burnout risk) trained on synthetic employee behavioral data, with a Streamlit dashboard for interactive predictions.

What it does

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.

Data

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_WEIGHTS in 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

Methodology

  1. Stratified 80/20 train/test split (src/data_loader.py)
  2. Standardization via StandardScaler (fit on train only)
  3. Two baselines are trained for comparison:
    • Majority-class dummy classifier (accuracy floor)
    • Logistic Regression
  4. One additional candidate: Random Forest (200 trees, max depth 10)
  5. Each real model (not the dummy) is evaluated with 5-fold stratified cross-validation on the training set
  6. The "final model" is not hardcoded. src/train.py selects whichever of Logistic Regression / Random Forest has the higher mean CV accuracy, and that's what gets saved and used by the app
  7. Final reported numbers come from the untouched 20% test set

Results

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.

How to reproduce these results

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.ipynb

reports/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.

Running the app

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.py

If models/burnout_model.joblib doesn't exist, app.py will train it automatically on first run (this takes a few seconds).

Project structure

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

Running tests

python -m pytest tests/ -v

Limitations

  • 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.

License

MIT

About

A project to know employees hard work and their burnout.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages