top of page

Tableau実践問題集 #TableauChallenge を作りました。

Fitbitのデータを可視化する


みなさんFitbitなどの活量計はお使いでしょうか。

自分はFitbit Inspire 3を使っているのですが、計測した日々の活動量や心拍数、睡眠のデータをFitbitアプリやダッシュボードで確認することができます。 特にアプリでは(有償/無償プランの差はありますが)詳細な時系列推移やアドバイスなどを確認できます。


(Fitbit ダッシュボード例)

ただしアプリにしてもダッシュボードにしても、表示単位は基本的に日次です。 一方で健康管理の観点で考えると、1日だけ多く活動する/睡眠を取れば良いということはなく、ある程度の期間は健康のための行動が必要なはずです。 例えば1週間ごとに見たときに、睡眠時間は継続的に7時間前後になっているのか、など...

またFitbitで計測される様々な指標のうち、自分の主な興味は活動量と睡眠に向いているのですが、それら数字を包括的かつ時系列的に確認することは(確認した限りでは)難しいようでした。

毎日アプリやダッシュボード上で複数回の操作や画面遷移を行うことも面倒なので、自分でデータをAPI経由で集約し、またTableau Publicでダッシュボード化することにしました。

そのダッシュボード化に際して行った内容を、2本の記事に分けて投稿します。

  1. データ取得と作成した可視化例の紹介編(この記事)

  2. Tableau Public上にある可視化のメール送信編


Fitbitをお持ちの方はスクリプトのコピペと多少の初期設定で同様のデータが取れるはずなので、ぜひ確認いただければと思います。

健康データを可視化してみたい方は是非チャレンジしてみてください。


作成したダッシュボードは以下からダウンロードできます。 https://tabsoft.co/3Tk8P8u 参考までに、サンプルデータを以下に格納しました。 https://docs.google.com/spreadsheets/d/1P0VnDQ2duZ_5of_3NdGxhpJG9WDxV1LkcLVZiU000C4/edit?usp=sharing

 

免責事項

  • 今回紹介するスクリプトは、各自のFitbitデバイスから計測したデータを、個人利用の範囲で利用することを想定しています。

  • ChatGPT 3.5と会話しながら作成したスクリプトです。また著者はスクリプト開発/プログラミングを専門としていません。ご了承ください。



 

前提知識

本記事ではGoogle Apps Scriptを使用してFitbit Web APIを利用し、Google Sheetsにデータを出力する処理を、スケジュール実行することを目指します。

したがって、最低限以下の内容について知る必要があります。

  1. Google SheetからGoogle Apps Scriptエディタを呼び出し、スクリプトを作成する

  2. スクリプトを定期実行するトリガーを設定する

  3. Fitbit APIを利用するための初期設定を行う


1と2についてはGoogle Apps Script 入門を、3についてはFitbitのWeb APIを実行する方法の「アクセス・トークンの取得手順 - Step 4: Get Tokens」までを参照ください。


 

事前準備

データの出力先のGoogle Sheetsが必要になります。 今回のスクリプトでは

  • 日次の歩数と心拍数のデータ

  • 日次の睡眠のサマリデータ

  • 睡眠の時系列データ

  • 日次の天気データ

に分けてデータを出力するため、サンプルデータを参考に、出力先のシートを4つご用意ください。


またFitbit APIの認証情報をJSONファイルに格納し、任意のGoogle DriveにそのJSONファイルを配置します。 下部の{}含めた文字列全てをテキストエディタ等にコピペし、以下1~3を実施ください。

  1. 各"YOUR_xxx"部分の値を、登録したFitbit Web API利用するアプリで設定された値に置き換える

  2. 拡張子.jsonで、任意の名前を付けて保存し、(他人に共有していない)Google Driveフォルダに格納する

  3. 共有URLを取得し、URLからファイルIDを控えておく (/d/~/viewまでの間の文字列。以下参照)

drive.google.com/file/d/(FILE_ID)/view?usp=sharing
{
  "client_id": "YOUR_OAuth2.0_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "access_token": "YOUR_ACCESS_TOKEN",
  "refresh_token": "YOUR_REFRESH_TOKEN"
}


 

スクリプトを設定する (Fitbitデータ取得編)

今回の処理で使用するスクリプトは以下から確認できます。 コピペ等をしてお使いください。


3つの.gsファイルがありますが、主要なスクリプトは Fitbit Data Collection.gs にあります。

このスクリプトでは大きく分けて3つの処理をしています。 (2と3の詳細は割愛します)

  1. 認証情報JSONファイルの指定、日付の指定、出力先の指定をする初期設定

  2. 認証情報の読み込みと更新

  3. データをFitbit Web APIで取得しGoogle Sheetsに格納


1の初期設定について、必須の設定項目は以下の4つです。

  • fileId

  • sheetHealth

  • sheetSleep

  • sheetSleepDetail

fileIdには先ほどのGoogle Drive ファイルIDを入れます。

sheetHealth/Sleep/SleepDetailの""部分には、作成した出力先シートの名前を入れます。

なお同じく初期設定項目にあるtargetDateRawですが、既定で昨日の日付が入ります。もし特定の日付のデータが必要な場合は直接指定することもできます。

またdateRangeはtargetDateRawから過去何日分のデータを取得するか指定します。 日次実行では0に設定しておけば良いです。


上記を正しく設定すれば、問題なくスクリプトは動くはずです。 一度手動実行してみると良いかと思います。その際はrefresh()を先に一度実行し認証情報を更新し、その後appendDataToFitbitSheets()を実行ください。

 

備考: 睡眠データの日付について

Fitbit APIでは睡眠データの日付 (dateOfSleep) は、睡眠が終了した日付で定義されています。 例えば2024/1/1のデータを活量と睡眠について、12/31の夜~1/1の朝まで睡眠したとして、ざっくりと言えば

  • 活量データ:1/1の日中~夜までの記録

  • 睡眠データ:12/31の夜~1/1の朝までの記録

となります。


したがって、上記の1/1のデータについては「多く活動した → 多く眠れた」という時系列ではなく「多く眠れた → 多く活動できた」という時系列になります。

活量を主目的として、睡眠を説明変数的に使用する場合には問題ないと思いますが、このスクリプトは睡眠を主目的、活量を説明変数的に扱うことを目的としているため、睡眠データの取得日付を1日未来にずらしています。 詳細はgetTargetDate()とfetchSleepData()部分を確認ください。


ちなみに夜勤などの理由から日次単位でのデータ取得では活量と睡眠の時系列を表現しにくい場合は、APIのEndpointをTime Series系のものに変え、時刻単位でデータを取るしかないのかなぁ...と想像します。


 

そしてデータを日次で追加したいので、2と3の処理にトリガーを設定します。

当日の睡眠ログが計測できた後にデータ取得としたいので、例えば3の処理 appendDataToFitbitSheets() を朝9時-10時の実行に設定し、2の処理 refresh() は3の処理より少し前に実行するように設定します。


ここまでで主要なデータを日次で取得するための準備が整いました。 ただし分析や運用上、もう少し用意しておきたいデータと処理がありましたので、以下でそちらについて記載します。



 

スクリプトを設定する (天気データとログ消去編)

やりたいことは過去の天気データの取得および睡眠の時系列データの定期削除です。

まず天気データについて、台風など外出がそもそも難しく、そのため歩数も稼げない日があることは想像できます。 データにそのような背景情報を追加するために、簡単に取れる範囲で天気データも取得します。 Daily Weather Data Collection.gs がそのスクリプトです。

ここではOpen-MeteoのAPIを使用しています。 同様にスクリプト中で多少の初期設定が必要です。 ここではシート名と緯度経度を設定すれば問題ありません。

var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("YOUR_SHEET_NAME");
var lat = 0;  // Enter your taregt location's latitude
var lon = 0;  // Enter your taregt location's longitude
var days = 1; // Enter the number of past days for which you want to fetch weather data

こちらも同様にトリガーを設定し、日次でデータが追加されるようにします。 次に睡眠の時系列データの削除について、1回の睡眠で20前後の行数(睡眠パターンによる)が記録されるので、例えば1年間で7000行程度になります。 今回の可視化ではそこまで過去のデータは不要なので、定期的に過去180日程度のデータだけ保持されるようにしました。

Fitbit Sleep Detail Data Deletion.gsがそのスクリプトです。


このスクリプトで設定が必要な個所は以下2つの変数です。

// Get the sheet named "Fitbit Sleep Detail"
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEETNAME_FOR_SLEEP_DETAIL_DATA");

// Specify the number of days before the current date to consider for deletion
var daysThreshold = 180; 

sheetの""内に睡眠の時系列データを格納しているシート名を、daysThresholdには保持したい日数を入力ください。

こちらも同様にトリガーを設定し、定期実行されるようにすると良いと思います。


ここまでの内容で、日次で必要なデータが出力されるようになりました。

出力例はサンプルデータを確認ください。




 

ダッシュボード例の紹介

必要なデータが揃ったので、Tableauで可視化をしてみます。

以下は作成したダッシュボード例です。以下目的に合わせて2つ作成しました。

  • 直近7日間の各指標について、目標比での平均の評価と推移および睡眠ログの可視化

  • 昨日の各指標についての評価と睡眠ログの可視化、過去28日間との比較




詳細な作り方はWorkbookのダウンロード等で中身を確認いただくとして、ここでは要点をいくつか記載します。


まずデータソースですが、日次のデータ(歩数と心拍数、睡眠サマリ、天気)と時系列の睡眠ログデータを1つにまとめています。 各データはDateで結合し、Densification Dummyは下図のようにCROSS JOINさせています。

睡眠ログデータについて、1行にある状態(覚醒状態、レム睡眠状態など)に入った時間と、その状態が続いた時間が記録されています。 各状態に入った開始点と終了点の2点を表示した可視化を作るため、Data Densification用のシートを用意して結合し、1行を2行に増やせるようにします。

サンプルデータのDensification Dummyシートを参照ください)


以下、各ダッシュボードの要点を記載します。 またダウンロード後に接続先を差し替えればそのまま使用できるはずなので、ご興味あればご自由にお使いください。

使用している計算式や可視化のテクニックもやや複雑な内容ありますので、技術的な内容に興味ある方もぜひ。


 

週次サマリダッシュボードについて


このダッシュボードの上段では、各指標の目標値をパラメータで設定しそれを基準に評価することで以下を確認することを目的としています。

  • 過去7日間を平均で見たとき、各指標は達成できていたか

  • 達成/未達成に影響した日はいつか

  • そもそも目標値は(過去28日間の実績から見て)妥当か


例えば睡眠時間は7時間 = 420分を目標として、それを達成できたかどうかを簡単に確認できるように設計しています。

また目標値の妥当性を確認するために、過去28日間の分布を右側に表示しています。感覚的には目標値が中央値付近なら妥当だと思いますが、あくまでも目安です。


そして下段の睡眠ログは、アプリの睡眠ログ表示を参考に作りました。

直近7日間の睡眠を、横軸を時刻か睡眠時間かを切り替えながら表示でき、傾向を視覚的に確認できます。 例えば、0時~6時の睡眠も2時~8時の睡眠も同じ6時間です。 しかし睡眠開始時刻も(諸説あるようですが)睡眠の質に影響するようなので、睡眠を時間と開始時刻の両面で評価できるようにしました。

 

日次ダッシュボードについて


このダッシュボードは日次でメール送信することを前提としているので、端的に「昨日の数字はどうだったか」が分かるように設計しました。


上段では各指標と目標との差が一目でわかり、右下のレーダーチャートで過去28日間ベースで見たときの程度感を、色と形で確認できるようにしています。

上記の場合、睡眠系の指標は冴えず、また睡眠時間と深い睡眠の割合が目標以下だったことが分かり、また特に歩数と心拍数が活発だった時間が優れていたことが分かります。 (要は、運動を頑張ったけど睡眠に現れなかった一日ですね)


ちなみにレーダーチャートは、一般的には1~5スケールのアンケート回答やパーセントなど上限/下限が決まっている指標に使われる印象ですが、このダッシュボードで扱っている指標の多くはどのような数字も取り得るので、各指標を0.2~1.2に正規化して上限/加減を計算させています。 実装についてはぜひダウンロードし確認してみて下さい。


 

備考: お昼寝した場合の睡眠データについて

お昼寝した場合も容赦なくログが取られます。 その場合は1日の睡眠時間や睡眠の時系列データに良くない影響を及ぼすので、以下どちらかが必要になります。

  • Fitbitなど計測側で該当のデータを手動削除する。

  • Tableau側で、睡眠IDごとの合計睡眠時間などでフィルターする。

自分は前者で対応しているのでTableau側のフィルターは特に実装していないのですが、そのうち後者を実装するかもです。ただ昼寝の定義が難しい気がするんですよね...


 

最後に

活量計のデータはなかなか面白かったです。

また計測によって改善できることもあると思いますので、Fitbitに限らず健康管理デバイスをお持ちの方はぜひデータ取得して分析や可視化をしてみると良いと思いました。


以下は次回予告ですが...作成したダッシュボードをTableau Publicに格納しましたが、データが日次更新されるなら可視化も日次か週次で見たいですよね。 ただしTableau Publicにアクセスして都度見ることもちょっと大変なので、画像をメール送信してくれるスクリプトを用意して定期実行します。

次回はその方法と、Tableau Publicのサブスクリプション的運用の限界について書きます。

長い記事となりました。ここまでお疲れさまでした。

質問などありましたら、XかLinkedinまでお願いします。


bottom of page