Skip to content

About

Sleep efficiency predictor from my first-author ICSMAI 2024 Springer paper (Random Forest, R2 0.8569) - Flask app with personalised recommendations

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

Repository files navigation

Sleep Efficiency Predictor

Ten answers about last night, and an estimate of how much of your time in bed you actually spent asleep.

Python Flask scikit-learn DOI License

The Random Forest from Comparative Analysis of Machine Learning Methods for Enhancing Sleep Efficiency and Prediction, wrapped in a Flask app you can run locally. The paper compared four regressors on 452 nights of sleep-study data. Random Forest won, at R² 0.8569 and MSE 0.0027, and this repository ships it.

Hammad Ahmad, M. Umar Khan and Maleeha Azam. First-author paper, ICSMAI 2024. In "Advances in Smart Medical, IoT and Artificial Intelligence", Information Systems Engineering and Management series, Springer Nature Switzerland, 2024, pages 3 to 15. doi.org/10.1007/978-3-031-66854-8_1

Full case study: hammadahmad.co.uk/projects/sleep-efficiency

The prediction form

A 60 year old smoker, sedentary, four drinks, five awakenings, and a night that was 60% light sleep against 25% deep, comes back at 0.58. That sits left of both cuts on the band ruler, and the advice that follows is to get assessed rather than to tweak a bedtime routine.

The result


The interface

Two pages, one stylesheet, no build step and no framework.

The sleep-stage composition readout, five short of 100

  • The three percentages are checked as you type. Deep, light and REM have to total 100, which is the model's own constraint. The panel beside those fields fills as you go and says how far off the total is, rather than rejecting the night after you have already submitted it.
  • Errors are visible. Field and radio errors were rendered nowhere before, so leaving a radio unset just redisplayed the form with no explanation.
  • The score lands on a scale. The result page puts it on the 0.50 to 1.00 axis the data actually spans, with the 0.64 and 0.80 cuts marked, instead of printing a bare number.
  • The inputs are grouped by what they are: the person, the night, the day before. Every numeric field carries the range the model was trained on, since nothing stops you entering a value from outside it.
  • Colour carries meaning. The same three hues are deep, light and REM wherever they appear, and amber is only ever an action.
  • Below 900px the layout collapses to one column and the readout sticks to the top of the screen, so it stays in view while the percentages are being typed.

Type is IBM Plex Mono for anything numeric or structural, Instrument Sans for prose. Both come from Google Fonts and fall back to system faces offline.


What sleep efficiency is

Time asleep divided by time in bed. Eight hours in bed and six and a half asleep is about 0.81. The app splits the range three ways:

Band Range What it means
High 0.80 and above Typical of healthy adults
Normal 0.64 to 0.79 Room to improve, mostly behavioural
Low below 0.64 Worth a clinical opinion

What the model learned

Feature importances for the Random Forest

Sleep architecture is almost the whole model. Deep sleep percentage, light sleep percentage and awakenings account for 87.7% of the forest's split importance between them. Everything a person controls directly on a given evening, caffeine at 0.7%, exercise at 1.2%, alcohol at 1.5%, is close to noise by comparison.

That is worth stating plainly, because it sets what the tool is for. It predicts efficiency well from measurements you need a sleep tracker to obtain. It is not a lifestyle calculator, and the inputs a person can act on are the ones it weighs least.

Correlation of each measure with sleep efficiency

The raw correlations agree. Light sleep runs against efficiency at -0.82 and deep sleep with it at +0.79, close to two views of one underlying quantity. Awakenings at -0.56 and alcohol at -0.39 come next. Total sleep duration is essentially unrelated at -0.03: how long you were in bed says almost nothing about how much of it you slept.

The numbers behind both charts

Feature importances, read from sleep_efficiency_model.pkl:

Feature Importance
Deep sleep percentage 0.3745
Light sleep percentage 0.3605
Awakenings 0.1420
Age 0.0405
Smoking status 0.0299
REM sleep percentage 0.0156
Alcohol consumption 0.0146
Exercise frequency 0.0124
Caffeine consumption 0.0071
Gender 0.0030

Regenerate both charts with python tools/make_readme_charts.py.


The data

Sleep_Efficiency.csv, 452 nights across 15 columns. Efficiency runs from 0.50 to 0.99 with a median of 0.82, so the cohort skews towards good sleepers: 257 nights land in the high band, 119 normal, 76 low.

Four columns carry missing values, 65 cells in total, and dropping incomplete rows leaves 388 usable nights. REM, deep and light percentages sum to exactly 100 on every row, which is why the form rejects any combination that does not.


How it works

flowchart LR
  FORM[Flask form<br/>10 fields] --> V[validate<br/>REM + deep + light = 100]
  V --> VEC[feature vector<br/>ordered to match the model]
  VEC --> RF[(RandomForestRegressor<br/>100 trees)]
  RF --> BAND[band at 0.80 / 0.64]
  BAND --> OUT[score, colour, advice]
Loading

Two routes. / renders the form and handles the POST, /results/<prediction> renders the score. The model loads once at import.

The feature vector has to be built in the order the model was fitted in, which puts smoking status before exercise frequency. Passing a bare NumPy array means scikit-learn cannot check names, so getting that order wrong fails silently rather than raising.

The ten inputs
Field Type Range in the data
Age integer 9 to 69
Gender Female / Male
REM sleep percentage number 15 to 30
Deep sleep percentage number 18 to 75
Light sleep percentage number 7 to 63
Awakenings integer 0 to 4
Caffeine consumption mg 0 to 200
Alcohol consumption oz 0 to 5
Exercise frequency Sedentary to Heavy
Smoking status No / Yes

The three percentages must total 100. The form tracks that as you type and the server checks it again on submit.


Run it

Requires Python 3.11.

git clone https://github.com/1oNN/sleep-efficiency-app.git
cd sleep-efficiency-app

python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -r requirements.txt

python app.py                    # http://localhost:5000

The scikit-learn pin matters. The model was serialised under scikit-learn 1.3, and 1.4 changed the tree internals, so a newer release imports the pickle without complaint and then raises on the first prediction. If you want a current scikit-learn, retrain rather than force the load. Set PORT if 5000 is already taken.

Docker works as well:

docker compose up -d

Limitations

  • 452 nights is a small dataset, from one sleep study, skewed towards good sleepers. Treat this as a demonstration of the paper's method rather than a general instrument.
  • The strongest inputs need a sleep tracker. Deep and light sleep percentages are not values you can estimate honestly from memory, and they dominate the prediction.
  • The form offers four exercise levels, the data has six. Training used frequency 0 to 5; the radio buttons stop at 3, so the top two levels cannot be entered.
  • The form accepts values the model never saw. Inputs cap at sane bounds rather than at the training range, and the hint under each field says what that range was. Anything outside it still produces a number, and it will not mean much.
  • A research artifact, not a medical device. It cannot diagnose a sleep disorder.

Citation

@incollection{ahmad2024sleep,
  author    = {Ahmad, Hammad and Khan, M. Umar and Azam, Maleeha},
  title     = {Comparative Analysis of Machine Learning Methods for Enhancing
               Sleep Efficiency and Prediction},
  booktitle = {Advances in Smart Medical, IoT and Artificial Intelligence},
  series    = {Information Systems Engineering and Management},
  publisher = {Springer Nature Switzerland},
  year      = {2024},
  pages     = {3--15},
  doi       = {10.1007/978-3-031-66854-8_1}
}

Machine-readable version in CITATION.cff.

License

MIT. See LICENSE.

About

Sleep efficiency predictor from my first-author ICSMAI 2024 Springer paper (Random Forest, R2 0.8569) - Flask app with personalised recommendations

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages