1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

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

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

事前準備と取れるデータ

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

どんなデータがとれる?

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

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

call_api.png

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

result-1024x860.png

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

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

problem-2-1024x628.png

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

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

proc_30sec.png

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

2024-10-20_16h44_15.png

さいごに

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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?