Details for fitbit_sleep_analysis.ipynb

Published by Wenqiu999

Description

Analysis of sleep data collected by Fitbit.

0

Tags & Data Sources

fitbit connection sleep fitbit connection

Comments

Please log in to comment.

Notebook
Last updated 4 weeks ago

This notebook is created to analyze sleep data collected by fitbit. It used public data as a demonstrate to show how the plots look like. You can use the code below to analyze your own sleep data. And This notebook is free to reuse and adapt, distributed under an MIT license: https://opensource.org/licenses/MIT

**Note: ** This notebook currently includes empty data (e.g. from dates the device wasn't worn) in averages - this may result in erroneous/misleading results. Fixes welcome and please share with wenqiu_cao@my.uri.edu.

In [1]:
import pandas as pd
import json
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import urllib
import requests
import os
import tempfile
from datetime import datetime
from ohapi import api

user_details = api.exchange_oauth2_member(os.environ.get('OH_ACCESS_TOKEN'))
for i in user_details['data']:
    if i['basename'] == 'fitbit-data.json' and i['source'] == 'direct-sharing-102':
        fitbit = requests.get(i['download_url']).json()
In [3]:
DateTime = []

You can choose the year you want to analyze.

In [4]:
year = '2018'
In [5]:
def GetData(obj,year,key):
    name = key.split('-')[-1]
    name = []
    for day in fitbit[obj][year][key]:
        name.append(day['value'])
    return name

for day in fitbit['minutes-to-sleep'][year]['sleep-minutesToFallAsleep']:
    DateTime.append(datetime.strptime(day['dateTime'],'%Y-%m-%d'))
    

    
sleepData = pd.DataFrame(
    data = {
        'minutesToFallAsleep': GetData('minutes-to-sleep',year,'sleep-minutesToFallAsleep'),
        'minutesAfterWakeup': GetData('sleep-minutes-after-wakeup',year,'sleep-minutesAfterWakeup'),
        'startTime': GetData('sleep-start-time',year,'sleep-startTime'),
        'minutesAwake': GetData('awake-minutes',year,'sleep-minutesAwake'),
        'timeInBed': GetData('time-in-bed',year,'sleep-timeInBed'),
        'awakeningsCount': GetData('sleep-awakenings',year,'sleep-awakeningsCount'),
        'sleepEfficiency': GetData('sleep-efficiency',year,'sleep-efficiency'),
        'minutesAsleep':GetData('sleep-minutes',year,'sleep-minutesAsleep')
        
    }
)
In [6]:
DateTime = pd.DataFrame(DateTime)
In [7]:
sleepData = pd.concat([DateTime, sleepData], axis=1)
sleepData.rename(columns={sleepData.columns[0]: 'DateTime'}, inplace=True)
sleepData = sleepData.set_index('DateTime', drop= False)

Are you getting the required hours of sleep? - Average sleep hours and the deviation;

In [8]:
import matplotlib.dates as mdates

sleepData['timeInBed'] = sleepData['timeInBed'].astype(float)
sleepData['hourInBed'] = sleepData['timeInBed']/60
sleepDesc = pd.DataFrame(sleepData['hourInBed'].describe())
sleepDesc
Out[8]:
hourInBed
count 365.000000
mean 7.063470
std 1.697586
min 0.000000
25% 6.666667
50% 7.366667
75% 7.883333
max 10.233333
In [9]:
avgSleepHours = round(sleepDesc['hourInBed']['mean'],2)
summary = 'Averaging a sleep of {} hours with a deviation of {} hours'.format(avgSleepHours, round(sleepDesc['hourInBed']['std'],2))

fig = plt.figure(figsize = (20,6)) 
plt.hist(sleepData['hourInBed'], bins = 8, range = (3, 10), color="navy")
plt.xlim(3, 10)
plt.xticks(range(3, 10))
plt.xlabel('Hours in Bed')
plt.ylabel('Count');
plt.title(summary, fontsize=15)
plt.show()
In [10]:
fig, ax = plt.subplots(figsize = (20,6))
plt.plot(sleepData['DateTime'],sleepData['hourInBed'], linestyle='-', 
         markersize=10, color='c', label='% Light', linewidth=3.0, alpha=0.9)
plt.ylabel('hourInBed', fontsize=14)
plt.axhline(avgSleepHours, color="orangered", linestyle='--')
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%D'))
ax.grid(True)
plt.xticks(rotation=90)
plt.plot()
plt.show()

When you're in bed, you're not asleep all the time. Let's take a look at the sleep pattern while you're in bed.

In [11]:
SleepPattern = sleepData[['minutesAwake','minutesAsleep']].astype(float)
avgSleep = SleepPattern.mean()
In [12]:
fig = plt.figure(figsize = (6,6))
labels=['Awake', 'Asleep']
plt.pie(avgSleep, colors = ['lightskyblue', 'yellowgreen'], autopct='%1.1f%%', labels=labels, textprops=dict(color="w"))


my_circle=plt.Circle( (0,0), 0.7, color='white')
p=plt.gcf()
p.gca().add_artist(my_circle)

plt.title('Average of types of sleep', fontsize=14)
plt.legend()
plt.show()

Is there any pattern of your sleep based on different days of a week?

In [13]:
sleepData['Day of week'] = sleepData.index.weekday_name
weekday = ['Monday','Tuesday','Wednesday','Thursday','Friday']
weekend = ['Saturday','Sunday']
sleepData.loc[sleepData['Day of week'].isin(weekday), 'IsWeekday'] = 'TRUE'
sleepData.loc[sleepData['Day of week'].isin(weekend), 'IsWeekday'] = 'FALSE'
In [14]:
sleepData[['minutesAsleep', 'minutesAwake', 'sleepEfficiency']] = sleepData[['minutesAsleep', 'minutesAwake', 'sleepEfficiency']].astype(float)
dayGroupedData = sleepData.groupby(['Day of week']).mean()
dayGroupedData
Out[14]:
minutesAwake timeInBed sleepEfficiency minutesAsleep hourInBed
Day of week
Friday 54.576923 386.134615 82.884615 331.557692 6.435577
Monday 66.566038 436.207547 83.188679 369.641509 7.270126
Saturday 64.326923 441.038462 80.596154 376.634615 7.350641
Sunday 64.134615 440.596154 82.192308 375.288462 7.343269
Thursday 58.403846 420.980769 82.788462 362.461538 7.016346
Tuesday 64.538462 444.115385 83.807692 379.230769 7.401923
Wednesday 59.865385 397.346154 81.942308 337.423077 6.622436
In [15]:
dayofweek = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
fig = plt.figure(figsize = (14,5))
plt.bar((dayGroupedData.index), dayGroupedData['minutesAwake'],  width = 0.4, color='slateblue', label='Minutes Awake')
plt.bar((dayGroupedData.index), dayGroupedData['minutesAsleep'], width = 0.4, color='dodgerblue', label='Minutes Asleep', bottom=dayGroupedData['minutesAwake'])
plt.bar((dayGroupedData.index), dayGroupedData['timeInBed'],width = 0.4, color='lightskyblue', label='Time in Bed', bottom=dayGroupedData['minutesAsleep'])
plt.xticks(np.arange(len(dayofweek)),dayofweek)
plt.legend()
plt.show()
In [16]:
fig, ax = plt.subplots(figsize=(15, 9))
ax.plot('Day of week', 'timeInBed', data=sleepData, marker='o', markersize=8, linestyle='None', color ='salmon')
dayGroupedData = dayGroupedData.reset_index(drop=False)
ax.plot(dayGroupedData['timeInBed'],color='r', linewidth=2, label='Average Time in Bed' )
ax.set_ylabel('Time in Bed')
ax.set_xlabel('Day of Week')
plt.xticks(np.arange(len(dayofweek)),dayofweek)
plt.legend()
plt.show()

Let's check out how your sleep varies for weekdays vs weekends.

In [17]:
sleepData.groupby('IsWeekday').mean()
Out[17]:
minutesAwake timeInBed sleepEfficiency minutesAsleep hourInBed
IsWeekday
FALSE 64.230769 440.817308 81.394231 375.961538 7.346955
TRUE 60.812261 417.030651 82.923372 356.114943 6.950511
In [18]:
cols_plot = ['timeInBed','minutesAsleep', 'minutesAwake','sleepEfficiency']
axes = sleepData.groupby('IsWeekday')[cols_plot].mean().plot(kind='bar', figsize=(10, 20), subplots=True)
for ax in axes:
    ax.set_xlabel('Is Weekday', labelpad=10)
    ax.set_title('Weekday vs Weekend', fontsize=10)
plt.show()

The change of seasons may affect your sleep,too. Let's how your sleep changes over month in one year.

In [19]:
sleepData['Month'] = sleepData.index.month
In [20]:
fig, axes = plt.subplots(3, 1, figsize=(12,10), sharex=True)
for name, ax in zip(['timeInBed','minutesAsleep', 'minutesAwake'], axes):
    sns.boxplot(data=sleepData, x='Month', y=name, ax=ax)
    ax.set_ylabel('Minutes')
    ax.set_title(name)
    if ax != axes[-1]:
        ax.set_xlabel('')
plt.show()
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
/opt/conda/lib/python3.6/site-packages/seaborn/categorical.py:454: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  box_data = remove_na(group_data)
In [ ]: