データ取得

【Oura Ring×Web API】日々の睡眠情報を可視化しよう!【睡眠時間, 入眠時間, etc.】

こうらく

Oura Ringと呼ばれる指輪型のスマートデバイスでは、装着するだけで日々の睡眠情報やアクティビティ情報を収集することができます。

こちらの記事ではWeb APIを使ってアクティビティの情報を取るまでのステップをイチから紹介していますので、まずはこちらをご覧ください。

あわせて読みたい
【Oura Ring×Web API】毎日のアクティビティを可視化しよう!【歩数, 消費カロリー, 着座時間, etc.】
【Oura Ring×Web API】毎日のアクティビティを可視化しよう!【歩数, 消費カロリー, 着座時間, etc.】

本記事では、PythonからOura ringのWeb APIを使って睡眠情報の取り方を紹介します。また、分析しやすいよう、時系列のデータへの加工のコツも紹介します。

事前準備と取れるデータ

Web APIを使うためのトークン取得およびTalend API Testerでのデータ確認の方法は下記の記事の「Oura RingのWeb API」章をご覧ください。

あわせて読みたい
【Oura Ring×Web API】毎日のアクティビティを可視化しよう!【歩数, 消費カロリー, 着座時間, etc.】
【Oura Ring×Web API】毎日のアクティビティを可視化しよう!【歩数, 消費カロリー, 着座時間, etc.】

どんなデータがとれる?

睡眠時間は下記のエンドポイントから取得します。末尾の「sleep」で取るデータを分岐しています。アクティビティデータなら、画像の赤枠が「daily_activity」になります。 

https://api.ouraring.com/v2/usercollection/sleep

Web APIのコールに成功すると、各睡眠ごとの様々なデータが取得できます。

それぞれの指標の意味は下記のページが非常に参考になります。

ここで、上記画像のmovement_30_secを見てみると数値の羅列(322112…)になっています。Web APIのドキュメントを読んでみると、これはベッドに入ってから出るまでの時間に対して30秒ごとの動きのステータスになっているようです。

数値の羅列のままだと人が見ても当然何を意味しているのか分かりづらく、秒単位で細かく表現されているにもかかわらず暗黙的に時刻の情報が含まれていて分析しづらいです。この問題について、次章でどのように加工すればよいか紹介していきます!

Pythonで加工するためのポイント

データを取得・加工するまでのスクリプトは以下です。こちらのsrcフォルダのsleep.pyを利用ください。

前章でも述べた通り、睡眠情報には睡眠中の30秒ごとの動きのステータスおよび5分ごとの眠りの深さのステータスが数値の羅列(例:44422211111…)として表現されています。分析する上では非常に扱いづらく、人が見る上でもわかりづらいです。

紹介したスクリプトでは、これらを開始時刻と終了時刻の列に展開できるようになっています。

#-- 抜粋 --#

# movement_30_sec
for b_data in data:
    start_timestamp = datetime.datetime.strptime(b_data["bedtime_start"][:-6], '%Y-%m-%dT%H:%M:%S')
    end_timestamp = datetime.datetime.strptime(b_data["bedtime_start"][:-6], '%Y-%m-%dT%H:%M:%S') + datetime.timedelta(seconds = MOVEMENT_INTERVAL)
    for status_number in b_data["movement_30_sec"]:
        movement_30_sec["id"].append(b_data["id"])
        movement_30_sec["start_recording"].append(start_timestamp)
        movement_30_sec["end_recording"].append(end_timestamp)
        movement_30_sec["status_number"].append(status_number)
        start_timestamp = start_timestamp + datetime.timedelta(seconds = MOVEMENT_INTERVAL)
        end_timestamp = end_timestamp + datetime.timedelta(seconds = MOVEMENT_INTERVAL)
output_file_path = args.output_path + "/sleep_movement30sec_" + args.start_date + "~" + args.end_date + ".csv"
pd.DataFrame(data = movement_30_sec).to_csv(output_file_path, encoding = "utf-8", index = False)

# sleep_phase_5_min
for b_data in data:
    start_timestamp = datetime.datetime.strptime(b_data["bedtime_start"][:-6], '%Y-%m-%dT%H:%M:%S')
    end_timestamp = datetime.datetime.strptime(b_data["bedtime_start"][:-6], '%Y-%m-%dT%H:%M:%S') + datetime.timedelta(minutes = SLEEP_5_MIN_INTERVAL)
    for status_number in b_data["sleep_phase_5_min"]:
        sleep_phase_5_min["id"].append(b_data["id"])
        sleep_phase_5_min["start_recording"].append(start_timestamp)
        sleep_phase_5_min["end_recording"].append(end_timestamp)
        sleep_phase_5_min["status_number"].append(status_number)
        start_timestamp = start_timestamp + datetime.timedelta(minutes = SLEEP_5_MIN_INTERVAL)
        end_timestamp = end_timestamp + datetime.timedelta(minutes = SLEEP_5_MIN_INTERVAL)
output_file_path = args.output_path + "/sleep_sleepphase5min_" + args.start_date + "~" + args.end_date + ".csv"
pd.DataFrame(data = sleep_phase_5_min).to_csv(output_file_path, encoding = "utf-8", index = False)
loop_cnt+=1

こちらをステータスマスタと紐づけることで、「n時からm時まではどんな状態だったか」といった形で可視化が可能です。

さいごに

本記事では一般的な睡眠スコアだけでなく、分析を意識し時系列でも細かく追えるように加工する方法を紹介しました。是非日々の睡眠改善に役立ててみてくださいね!睡眠の浅さからストレスの塩梅がわかったり、もしかしたら睡眠時無呼吸症候群の早期発見に役立つかも!?しれません。

ABOUT ME
こうらく
こうらく
データエンジニア
記事を読んでいただいている皆さんが理解しやすくかつ手軽に試せることを意識して、データの蓄積、加工、分析・可視化のノウハウを発信していきます!Pythonを使ったデータ収集基盤作成及びそのノウハウ発表で登壇したりしています。
記事URLをコピーしました