fitbit

概説(そのうち詳しく書く)

fitbit Charge HR を買った。2015年12月4日夜に届いたので,さっそく翌日のR研究集会に付けていった。

fitbitのWebサイトやアプリでのデータ閲覧は無料。データのダウンロードは有料である一月分のデータなら無料でダウンロードできるが,日ごとの代表値だけなので,内容が薄い。幸い,Rの fitbitScraper というパッケージを使えば,Webサイトからデータをスクレープして取得できる。

出力の形式はときどき変わるようなので,確認が必要。

install.packages("fitbitScraper")
library(fitbitScraper)

cookie = login(email="メールアドレス", password="パスワード")
steps = get_intraday_data(cookie, what="steps", date="2015-12-05")
distance = get_intraday_data(cookie, what="distance", date="2015-12-05")
floors = get_intraday_data(cookie, what="floors", date="2015-12-05")
active_minutes = get_intraday_data(cookie, what="active-minutes", date="2015-12-05")
calories_burned = get_intraday_data(cookie, what="calories-burned", date="2015-12-05")
heart_rate = get_intraday_data(cookie, what="heart-rate", date="2015-12-05")

これで1日分のデータが取得できる。次は心拍数のプロットである。

t = heart_rate$time
h = ifelse(heart_rate$bpm == 0, NA, heart_rate$bpm)
plot(t, h, type="l", col="#f39800", lwd=2, xlab="", ylab="",
     xlim=as.POSIXct(c("2015-12-05 06:00","2015-12-05 22:00")),
     las=1, panel.first=grid(NA,NULL))
心拍数

心拍数以外は15分きざみだが,心拍数は5分きざみの数値が得られる。ちなみに,iOSのfitbitアプリでは次のようなグラフになる。

心拍数

睡眠データについては例えば get_sleep_data(cookie, "2016-01-08", "2016-01-10") とすれば1月8〜10日の毎日の(つまり前日夜から当日朝までの)睡眠データが取得できる。取得できるのは睡眠開始時刻・終了時刻・覚醒回数・寝返り回数などである。スマホを使えば,グラフ(画像)で個々の覚醒時刻・寝返り時刻が次のように表示できる:

睡眠

RでfitbitとJawboneから睡眠データを取得するによれば,APIを使えば上のような図を描くデータが取得できるらしい。あとでやってみよう。

1日の心拍数の変化

心拍数についてはKarvonenの式というのがあり,安静時心拍数と最大心拍数の間で運動強度を0%から100%まで目盛る。最大心拍数の推定値としては220から年齢を引く。私の場合,安静時心拍数を60bpm,年齢を5歳刻みに丸めて最大心拍数を220-65=155とした。

次のようなスクリプトを作っておく。

#! /usr/local/bin/Rscript

if (!require(fitbitScraper)) {
    install.packages("fitbitScraper")
    if (!require(fitbitScraper)) q("no", 1)
}
cookie = login(email="...", password="...")
today = as.character(Sys.Date())
heart_rate = get_intraday_data(cookie, what="heart-rate", date=today)

png("heartrate.png", width=750, height=350, type="cairo")

t = heart_rate$time
h = ifelse(heart_rate$bpm == 0, NA, heart_rate$bpm)

high = 220 - 65  # 220 - age (approximate)
low = 60
r = seq(0, 100, 20)
s = low + r * (high - low) / 100
tt = seq(as.POSIXct(paste(today, "06:00")), by=3600, length.out=18)

par(mar=c(3,3,1,4)+0.1, mgp=c(2,0.8,0), las=1)
plot(t, h, type="l", col="#f39800", lwd=2, xlab="", ylab="",
     xlim=as.POSIXct(paste(today, c("06:00", "23:00"))), ylim=c(low,high),
     panel.first=abline(h=s, v=tt, col="lightgray", lty="dotted"), xaxt="n")
axis(1, at=tt, labels=6:23)
axis(4, at=s, labels=paste0(r,"%"))

dev.off()

crontabに次のように登録する:

0 7-23 * * * /.../.../.../fitbit.R >/dev/null 2>&1

例として上と同じデータを使うと次のようになる(cairoではなくquartzデバイスに出力):

心拍数

安静時心拍数

1日の心拍数の変化もおもしろいが,毎日の安静時心拍数をプロットすると,風邪をひいたなどの体調の悪い日が歴然と現れる(図は省略する)。

rhr = get_daily_data(cookie, what="getRestingHeartRateData",
                     start_date="2016-01-01", end_date="2016-08-10")
plot(as.POSIXct(rhr$time), rhr$restingHeartRate, pch=16, type="o")

上の plot() のオプションは適当である。特に時間軸をわかりやすくする方法は時系列データを参照されたい。

睡眠

睡眠データは次のようにして取得できる:

sleep = get_sleep_data(cookie, start_date="2016-07-01", end_date="2016-08-10")

結果のデータ構造は str(sleep) と打ち込んで出てくる長いリストを読めばよいが,ややこしいので,以下では実例で示す。

sleep$df$date
[1] "2016-07-18" "2016-07-29" "2016-08-01" "2016-08-02" "2016-08-03"
[6] "2016-08-04" "2016-08-10"

この4番目の日(2016-08-02)は,出張でホテルの環境が悪く,最悪の睡眠状態であった。スマホのツールで見ると次のような感じである:

酷い睡眠状態の例
sleep$df[4,]$date
[1] "2016-08-02"
sleep$df[4,]$startDateTime
[1] "2016-8-01 23:11:00"
sleep$df[4,]$endDateTime
[1] "2016-8-02 06:40:00"
sleep$df[4,]$sleepDuration
[1] 449
sleep$df[4,]$breaks
[[1]]
   startTime magnitude duration            startDateTime
1      23:23         2        3 2016, 8, 1, 23, 23, 0, 0
2      23:27         2        1 2016, 8, 1, 23, 27, 0, 0
3      23:28         3        6 2016, 8, 1, 23, 28, 0, 0
4      23:34         2        3 2016, 8, 1, 23, 34, 0, 0
5      23:39         2        1 2016, 8, 1, 23, 39, 0, 0
6       0:33         2        1  2016, 8, 2, 0, 33, 0, 0
7       0:40         2        1  2016, 8, 2, 0, 40, 0, 0
8       0:42         2        6  2016, 8, 2, 0, 42, 0, 0
9       2:12         2        1  2016, 8, 2, 2, 12, 0, 0
10      2:52         2        1  2016, 8, 2, 2, 52, 0, 0
11      3:34         2        1  2016, 8, 2, 3, 34, 0, 0
12      3:57         2        1  2016, 8, 2, 3, 57, 0, 0
13      4:53         2        5  2016, 8, 2, 4, 53, 0, 0
sleep$df[4,]$breaks[[1]]$startTime
 [1] "23:23" "23:27" "23:28" "23:34" "23:39" "0:33"  "0:40"  "0:42"  "2:12" 
[10] "2:52"  "3:34"  "3:57"  "4:53" 
sleep$df[4,]$breaks[[1]]$startDateTime[[13]]
[1] 2016    8    2    4   53    0    0

図と見比べれば,magnitude2 は「寝返りを繰返す状態」,3 は「目覚めた状態」であることがわかる。duration は分単位のようだ。

これはかなり悪い例で,快眠の場合は寝返りも目覚めもゼロである。

このデータをリアルタイムで取得して(実際にはポーリング回数を頻繁にして)最適な時刻に目覚ましを鳴らす(あるいはfitbitのバイブ機能で目を覚まさせる)ことは研究課題である。