A R notebook to analyze your sleep and step data recorded by a Pebble watch
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

288 wiersze
8.3KB

  1. ---
  2. title: "Health stats"
  3. output:
  4. html_document:
  5. toc: yes
  6. pdf_document: default
  7. html_notebook:
  8. code_folding: hide
  9. toc: yes
  10. ---
  11. ```{r setup, include=FALSE}
  12. knitr::opts_chunk$set(echo = FALSE, warning = FALSE)
  13. ```
  14. # Summary
  15. This documents provides an overview of health data recorded by *Gadgetbridge* using a *Pebble* smartwatch.
  16. # Preparation
  17. Put the *GadgetBridge* database in the current folder, then knit the current `.Rmd` file.
  18. You should also set you **timezone** in the corresponding variable.
  19. * `PEBBLE_HEALTH_ACTIVITY_SAMPLE` is a simple table containing steps and timestamps.
  20. * `PEBBLE_HEALTH_ACTIVITY_OVERLAY` is more complex. It tracks activities (sleep, deep sleep, nap…) with a start and an end date. Note that date may overlap: you can be both in sleep and deep sleep.
  21. I have decided that any event happening after 8pm is registered for the next day. For instance:
  22. * if you go to bed at 9pm on Tuesday and wake up at 7am on Wednesday, the data will return 10 hours of sleep on Wednesday
  23. * if you go to bed at 7pm on Tuesday, a part of your sleep will be added to Tuesday. The cutoff won't exactly be 8pm, it will depend on the duration of the first sleep session recorded by you watch.
  24. ```{r include=FALSE}
  25. # Load data ------------------------------------------------------------------
  26. library(DBI)
  27. library(RSQLite)
  28. library(tidyverse)
  29. library(lubridate)
  30. library(scales)
  31. con <- DBI::dbConnect(RSQLite::SQLite(), dbname = "gadgetbridge")
  32. steps_data <- dbReadTable(con, "PEBBLE_HEALTH_ACTIVITY_SAMPLE")
  33. sleep_data <- dbReadTable(con, "PEBBLE_HEALTH_ACTIVITY_OVERLAY")
  34. dbDisconnect(con)
  35. #str(steps_data)
  36. # Transform data -------------------------------------------------------------
  37. ## Interprate timestamp
  38. timezone = "Europe/Paris"
  39. steps_data$datetime <- as_datetime(steps_data$TIMESTAMP)
  40. sleep_data$datetime_from <- with_tz(as_datetime(sleep_data$TIMESTAMP_FROM), timezone)
  41. sleep_data$datetime_to <- with_tz(as_datetime(sleep_data$TIMESTAMP_TO), timezone)
  42. ## Calculate activity duration
  43. ## Data recorded after 8pm is attached to the next day
  44. sleep_data$day <- date(sleep_data$datetime_from + hours(4))
  45. sleep_data$duration <- int_length(
  46. sleep_data$datetime_from %--% sleep_data$datetime_to
  47. ) / period_to_seconds(minutes(1))
  48. sleep_data$bed_time <- case_when(
  49. sleep_data$RAW_KIND == 1 ~ sleep_data$datetime_from
  50. )
  51. sleep_data$wakeup_time <- case_when(
  52. sleep_data$RAW_KIND == 1 ~ sleep_data$datetime_to
  53. )
  54. ## Convert RAW_KIND to the corresponding activity and summarize values
  55. sleep_data <- sleep_data %>%
  56. spread(RAW_KIND,duration,sep="_") %>%
  57. group_by(day) %>%
  58. summarise(
  59. sleep = sum(RAW_KIND_1, na.rm = TRUE),
  60. deep_sleep = sum(RAW_KIND_2, na.rm = TRUE),
  61. nap = sum(RAW_KIND_3, na.rm = TRUE),
  62. deep_nap = sum(RAW_KIND_4, na.rm = TRUE),
  63. walk = sum(RAW_KIND_5, na.rm = TRUE),
  64. run = sum(RAW_KIND_6, na.rm = TRUE), # Really not sure about this one
  65. bed_time = min(bed_time, na.rm = TRUE),
  66. wakeup_time = max(wakeup_time, na.rm = TRUE)
  67. )
  68. ```
  69. # Visualisation
  70. ## Steps
  71. ### Distribution of steps
  72. ```{r}
  73. data <- steps_data %>%
  74. mutate(date = date(datetime)) %>%
  75. select(date,STEPS) %>%
  76. group_by(date) %>%
  77. summarise(steps = sum(STEPS))
  78. ggplot(data, aes(steps)) +
  79. geom_histogram(binwidth = 500) +
  80. theme_minimal() +
  81. labs(x="Steps", y="Number of occurences")
  82. ```
  83. ### Distribution of steps per day of week
  84. ```{r}
  85. data <- steps_data %>%
  86. mutate(
  87. date = date(datetime),
  88. wday = wday(
  89. datetime,
  90. label = TRUE,
  91. week_start = getOption("lubridate.week.start", 1)
  92. )
  93. ) %>%
  94. select(date, wday, STEPS) %>%
  95. group_by(date, wday) %>%
  96. summarise(steps = sum(STEPS))
  97. ggplot(data, aes(x=wday,y=steps)) +
  98. geom_boxplot() +
  99. theme_minimal() +
  100. labs(x="Day of week", y="Number of steps")
  101. ```
  102. ### Number of steps per month
  103. ```{r}
  104. data <- steps_data %>%
  105. mutate(month = floor_date(datetime, unit = "month")) %>%
  106. select(month,STEPS) %>%
  107. group_by(month) %>%
  108. summarise(steps = sum(STEPS))
  109. ggplot(data, aes(x=month, y=steps)) +
  110. geom_col() +
  111. scale_x_datetime(labels = date_format("%Y-%m")) +
  112. scale_y_continuous(
  113. breaks = seq(0,500000,50000),
  114. labels=function(x) format(x, big.mark = " ")
  115. ) +
  116. geom_smooth(method = lm) +
  117. theme_minimal() +
  118. labs(x="Month", y="Number of steps")
  119. ```
  120. ### Average number of steps per hour of the day, year after year
  121. ```{r}
  122. data <- steps_data %>%
  123. mutate(
  124. date = date(datetime),
  125. time = datetime-floor_date(datetime, unit="day"),
  126. year = year(datetime)
  127. ) %>%
  128. group_by(date) %>%
  129. mutate(cumsteps = cumsum(STEPS)) %>%
  130. select(date, time, year, cumsteps) %>%
  131. ungroup() %>%
  132. group_by(time, year) %>%
  133. summarise(min = min(cumsteps), max = max(cumsteps), average = mean(cumsteps))
  134. ggplot(data) +
  135. geom_step(aes(x=time, y=average)) +
  136. theme_minimal() +
  137. labs(title = "Average number of steps per hour of the day", x="Hour", y="Number of steps") +
  138. scale_x_continuous(
  139. breaks = seq(
  140. 0,
  141. period_to_seconds(hours(24)),
  142. period_to_seconds(hours(1))
  143. ),
  144. labels = seq(0,24,1)
  145. ) +
  146. facet_wrap(vars(year))
  147. ```
  148. ### Active time per week
  149. ```{r}
  150. data <- sleep_data %>%
  151. mutate(
  152. wday = wday(
  153. day,
  154. label = TRUE,
  155. week_start = getOption("lubridate.week.start", 1)
  156. )
  157. ) %>%
  158. select(day, wday, walk) %>%
  159. group_by(day, wday) %>%
  160. summarise(walk_time = sum(walk)/60)
  161. ggplot(data, aes(x=wday,y=walk_time)) +
  162. geom_boxplot() +
  163. theme_minimal() +
  164. labs(x="Day of week", y="Hours active")
  165. ```
  166. ## Sleep
  167. ### Distribution of sleep duration
  168. ```{r}
  169. data <- sleep_data %>%
  170. group_by(day) %>%
  171. summarise(sleep_duration = sum(sleep)/60)
  172. ggplot(data) +
  173. geom_histogram(aes(sleep_duration), bins = 50) +
  174. scale_x_continuous(breaks = seq(0,12,1)) +
  175. theme_minimal() +
  176. labs(x="Sleep duration (hours)", y="Number of occurences")
  177. ```
  178. ### Distribution of deep sleep duration
  179. ```{r}
  180. data <- sleep_data %>%
  181. group_by(day) %>%
  182. summarise(deep_sleep_duration = sum(deep_sleep)/60)
  183. ggplot(data) +
  184. geom_histogram(aes(deep_sleep_duration),bins = 50) +
  185. scale_x_continuous(breaks = seq(0,12,1)) +
  186. theme_minimal() +
  187. labs(x="Deep sleep duration (hours)", y="Number of occurences")
  188. ```
  189. ### Distribution of sleep duration per day of week, year after year
  190. ```{r}
  191. data <- sleep_data %>%
  192. mutate(
  193. wday = wday(
  194. day,
  195. label = TRUE,
  196. week_start = getOption("lubridate.week.start", 1)
  197. ),
  198. year = year(day)
  199. ) %>%
  200. select(year, day, wday, sleep) %>%
  201. group_by(year, day, wday) %>%
  202. summarise(sleep_duration = sum(sleep)/60)
  203. ggplot(data, aes(x=wday,y=sleep_duration)) +
  204. geom_boxplot() +
  205. theme_minimal() +
  206. labs(x="Day of week", y="Sleep duration") +
  207. facet_grid(rows = vars(year), )
  208. ```
  209. ### Distribution of nap duration
  210. ```{r}
  211. data <- sleep_data %>%
  212. filter(nap > 0) %>%
  213. group_by(day) %>%
  214. summarise(nap_time = sum(nap))
  215. ggplot(data) +
  216. geom_histogram(aes(nap_time), bins = 10) +
  217. scale_x_continuous(breaks = seq(0,240,15)) +
  218. theme_minimal() +
  219. labs(x="Nap duration (minutes)", y="Number of occurences")
  220. ```
  221. ### Time of bed and waking up by year
  222. ```{r}
  223. data <- sleep_data %>%
  224. mutate(
  225. year = year(day),
  226. month = floor_date(day, unit = "month"),
  227. bed_time_hms = hms::as.hms(
  228. period_to_seconds(
  229. hours(hour(bed_time)) + minutes(minute(bed_time))
  230. )
  231. ),
  232. wakeup_time_hms = hms::as.hms(
  233. period_to_seconds(
  234. hours(hour(wakeup_time))+minutes(minute(wakeup_time))
  235. )
  236. )
  237. ) %>%
  238. drop_na(bed_time_hms) %>%
  239. drop_na(wakeup_time_hms)
  240. ggplot(data) +
  241. geom_histogram(aes(bed_time_hms), fill="orange", alpha=0.5, bins=30) +
  242. geom_histogram(aes(wakeup_time_hms), fill="blue", alpha=0.5, bins=30) +
  243. scale_x_continuous(
  244. breaks = seq(
  245. 0,
  246. period_to_seconds(hours(24)),
  247. period_to_seconds(hours(1))
  248. ),
  249. labels = seq(0,24,1)
  250. ) +
  251. theme_minimal() +
  252. labs(x="Bed time and wakeup time", y="Number of occurences") +
  253. facet_grid(rows = vars(year),scales="free_y")
  254. ```