NikeRunClubのデータ取得を効率化+解析したら新たなトレーニング指標が得られた件

## 狙い

最近膝を怪我したこともあり，再度データ分析に力を入れ始めた．．．
以前にNikeRunClubに集積された走行データをAPIを用いて取得する方法を[記事](https://qiita.com/h_funa/items/a9950dccd6bb4d4cf750 "NikeAPI")にまとめた．しかしながら，実際に解析を進めるにあたり以下のような課題がある．

- 取得されるJSONデータが解析向きでなく，生データだと扱いづらい
- ランごとのサマリーデータを扱いたい場合と時系列で扱いたい場合で区別する必要があり扱いづらい
- 以前の記事ではデータをbashで取得していたが，解析作業を考えるとpython等で取り扱いできたほうが楽
- 全データを毎度取得しているとサーバに負荷もかかるし，スクリプト処理時間も伸びるので必要なデータだけを取得したい（解析だけなら毎度取得も不要)

上記を改善するスクリプトを作成し，実際にデータを解析したので一例をここに共有する．(GWの暇つぶし)
実際にデータを解析することで，トレーニングの効果指標として心肺能力を評価できる新たな指針を得られた．

## 対象とする読者
- 自分の走行データを自分なりに解析したいと考えている人(今回はNikeだが，Stravaも概ね似たようなことは可能)
- データ分析に興味がある人

## スクリプトを用いたデータ取得+解析前準備
詳細な使用方法は以下のgitリポジトリのREADME.mdを参考　

https://github.com/HayatoFunahashi/RunAnlz

**[前提条件]**
- Nikeの走行データが存在すること
- デフォルトは心拍数データが含まれる走行データしか解析対象としない．心拍数データがないならNikeDataCollectorクラスのソースを触ること
- BearerTokenを取得し，Tokenファイルに保存しておくこと

**[取得できるデータ]**
① Summaryデータ
各走行の要約データをランごとに行に並べたデータフレームを返します．
count(=走行データ数)は環境に依存します．不要なデータはdropしておくのが良いと思います

```
Data columns (total 11 columns):
 #   Column               Non-Null Count  Dtype         
---  ------               --------------  -----         
 0   start_utc_ms         57 non-null     datetime64[ns] : 走行開始時刻
 1   active_duration_min  57 non-null     float64        : 総走行時間
 2   nikefuel             57 non-null     float64        : なぞ
 3   steps                57 non-null     int64          : ステップ数
 4   distance             57 non-null     float64        : 距離[km]
 5   speed                57 non-null     float64        : 速度[km/h]
 6   heart_rate           57 non-null     float64        : 平均心拍数
 7   ascent               35 non-null     float64        : 登坂距離
 8   calories             57 non-null     float64        : 消費カロリー
 9   pace                 57 non-null     float64        : ペース(min/km)
 10  descent              35 non-null     float64        : 下り距離
```

② Time-Seriesデータ
指定したmetricタイプに応じて，各ランの時系列データを並べたデータフレームを返します

```
 #   Column       Non-Null Count  Dtype         
---  ------       --------------  -----         
 0   start_utc    50 non-null     datetime64[ns] : 走行開始時刻
 1   data         50 non-null     object         : 時系列データ1(DataFrame)
```

ここでindex=1のdataは以下のDataframeで構成されます
```
Data columns (total 4 columns):
 #   Column          Non-Null Count  Dtype          
---  ------          --------------  -----          
 0   start_utc_ms    1481 non-null   datetime64[ns]  :開始時刻
 1   end_utc_ms      1481 non-null   datetime64[ns]  :終了時刻
 2   value           1481 non-null   float64         :metricの値
 3   dt_utc_ms       1481 non-null   timedelta64[ns] :走行開始からの差分時間
```

**[簡易説明]**
NikeAnlzerクラスのインスタンスを生成（生成時にNike.comからフェッチするか引数で指定します)
NikeAnlzerインスタンスのメンバーを呼び出しして，summaryかtime-seriesのデータを取得します（前処理して生成したデータフレームを返します)


### 改善点
Tokenが自動取得できないので期限が切れるたびに再更新する必要があります．自動でTokenを取得しようとしましたがロジックがわからず断念．良い方法あれば．．．　ブラウザでやってることを自動で実施すればできそうだが．．


## 解析データの一例
データ取得方法：Apple Watch 6+GPS
データ数：約50ラン

■各データの相関関係(pairplot分析)
![pairplot_org.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934349/91676237-7c54-7891-0382-73af2b2cd059.png)
- caloriesのデータは距離（時間）の１次関数である．ほぼ速度やペース，コースには依存しない．
    - 事前に決めた距離でカロリーは決まるということ
- paceとspeedは対称性があるので独立して評価する必要なし
- distanceと心拍数は対数関数っぽい傾向が見られる(走行距離30km以上のランを除く)
    - 一定以上走っても心拍数の上がり方には制限がある　短いランでも意識したら心拍数を上げれる可能性あり

■心拍数と距離の関係の考察
![hr_vs_dist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934349/c8b79853-7f71-1904-ae13-dc8922b87a43.png)

 - 25km以下のランにおいて,距離と心拍数は線形でなく対数関数的な傾向を示している．最初は楽で後半がしんどい傾向と一致している
   - ある程度の距離を走るとそれなりの心拍数で収束する
   - 心拍数を上げたいときは，そんなに距離はいらなくて，ある程度距離を稼げたら十分 10-15kmとかで良い
   - 同一距離であってもばらつきが存在しているのは，トレーニングセットの条件(例えばスピード）に依存しそう．そこで消費エネルギー（速度）が上がると心拍数も上がるという普遍的事実から心拍数/速度の比を取り平均値で規格化してみたのが下図．

![nominal_bpm_speed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934349/6b3064d8-1a41-196f-e571-567579d602f8.png)

- 物理的意味としてはどれだけの数の心拍数で一定距離を進んだかという指標になる．
- 距離に対して線形の特性を示す強い相関関係を示している
- **トレーニングの効果として自分の成長を量る指標として例えば，この値を低く走れる≒心肺能力が向上と見て良さそう**