【Python】Pandasのdataframeを使って体重周りの計算をしたお話

# Pandasのdataframeを使って体重周りの計算をしたお話
## 目的

- iOSヘルスケアのデータで除脂肪体重がハブられてるのがちょっと面倒くさい
    - というのも、除脂肪体重は筋肉の量に関係し、基礎代謝の目安にもなるため
- 除脂肪体重は体脂肪率の逆（下の式1）から求められる
- 基礎代謝は下の式2（または式2補足）で求められる
- 今回はヘルスケアのデータのエクスポートデータではなく、iOSアプリ(QSAccess)から得られたcsvファイルをもとに作成する。

### 式一覧

- 体重(Kg) W
    - Weightの略
- 体脂肪率(%) F
    - Fatの略、%値（実際にはcsv取り込み時に小数表記になる）
- 除脂肪体重(Kg) L
    - Lean Body Massの略
- 基礎代謝(kcal) B
    - base metabolismの略

#### 式1（除脂肪体重を求める）
```math
L = W \times \frac{100 - F}{100}
```

#### 式2（除脂肪体重から基礎代謝を求める）
```math
B = 370 + 21.6L
```

#### 式2補足（式2に式1を代入）
```math
B = 370 + (\frac{100 - F}{100} \times 21.6W)
```

#### 式3 BMIの算出

- 身長 H
    - BMIの計算ではm単位。Heightの略

```math
BMI = \frac{W}{H^2}
```

## Pandasとデータフレームの扱い

csvファイルを取り込んで計算するにあたって、Pandasというライブラリ（モジュール）とデータフレームという型に触れることになった。

### データフレームとは

（ざっくりとした理解では）表型のデータ種別。今回のようなcsvファイルのような形式がイメージとして近い。

### データフレームの列名を変更する

データフレームに対してrenameというメソッドで変更できる。[^1]

ちなみに、以下で'Start'を'日付'と変更しようとしているが、csv取り込み時に基準列に設定した列名は変更できない（らしい）。

```Python
    # データフレーム上の列名を変更
    df = df.rename(columns={'Start':'日付', \
            'Body Fat Percentage (%)': '体脂肪率', 'Weight (kg)': '体重'})  
```

参考: [pandas.DataFrameの行名・列名の変更 - note.nkmk.me](https://note.nkmk.me/python-pandas-dataframe-rename/)

[^1]: {'key': 'value'}で表されるのは辞書型のデータ

### 列の絞り込み

元データには時間帯・期間を表すStart, Finishという列があったが、今回はFinishは不要のため、基準列となっているStart以外のうち、体脂肪率と体重だけに絞り込むことにした。

```Python
    # データフレームの値列を体脂肪率と体重に絞る
    data = df[['体脂肪率', '体重']]
```

参考: [Pandas でデータフレームから特定の行・列を取得する - Python でデータサイエンス](https://pythondatascience.plavox.info/pandas/%E8%A1%8C%E3%83%BB%E5%88%97%E3%81%AE%E6%8A%BD%E5%87%BA)


### 無効データ(0で出力されたレコード)を除外する

計算するにあたって、体脂肪率・体重のどちらかが0だと意味の無いデータになってしまうため、どちらかが0の場合にレコードを除外する必要があった。

以下の、```data[data > 0]```が0より大きいデータを有効とする（0以下を無効とする）記述で、無効となった値を```data.dropna()```で除外している。

```Python
    # 0は欠損値として扱い、そのレコードを削除する
    data = data[data > 0]
    data = data.dropna()
```

参考

- 欠損値（外れ値）を除外: [pandasでよく使う文法まとめ - @okadate@Qiita](https://qiita.com/okadate/items/7b9620a5e64b4e906c42)
- 特定の条件の値を取得する: [Pandas でデータフレームから特定の行・列を取得する - Python でデータサイエンス](https://pythondatascience.plavox.info/pandas/%E8%A1%8C%E3%83%BB%E5%88%97%E3%81%AE%E6%8A%BD%E5%87%BA)

### 計算して出来た値を列として追加する

また、```data['列名'] = 値のリスト([])や計算式```という式を書くと、データフレームに列を追加できる。この計算式には列名を指定して、他の列の各行の値をそれぞれ計算に利用することが出来る。

なお、BMIの計算で使用している```(height ** 2)```は、height（身長(m)）の2乗を示している。(Pythonの構文)

```Python
    # BMI、除脂肪体重、基礎代謝(Katch-McArdle式:除脂肪体重から算出する式)を求める
    data['BMI'] = data['体重'] / (height ** 2)
    data['除脂肪体重'] = data['体重'] * (1 - data['体脂肪率'])
    data['基礎代謝'] = 370 + (21.6 * data['除脂肪体重'])
```

参考: [Pandas のデータフレームに行や列 (カラム) を追加する - Python でデータサイエンス](https://pythondatascience.plavox.info/pandas/pandas%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%81%AB%E8%A1%8C%E3%82%84%E5%88%97%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)

## あとは順次計算していくだけ

以下にこれまでのコードをまとめたソースコードを示します。

```Python:QSAccess.py
    # データフレーム上の列名を変更
    df = df.rename(columns={'Start':'日付', \
            'Body Fat Percentage (%)': '体脂肪率', 'Weight (kg)': '体重'})  

    # データフレームの値列を体脂肪率と体重に絞る
    data = df[['体脂肪率', '体重']]

    # 0は欠損値として扱い、そのレコードを削除する
    data = data[data > 0]
    data = data.dropna()

    # BMI、除脂肪体重、基礎代謝(Katch-McArdle式:除脂肪体重から算出する式)を求める
    data['BMI'] = data['体重'] / (height ** 2)
    data['除脂肪体重'] = data['体重'] * (1 - data['体脂肪率'])
    data['基礎代謝'] = 370 + (21.6 * data['除脂肪体重'])
```

## あとは

出来たcsvデータをExcelに取り込んで一部をグラフ化したり。結局、体重と比べやすい除脂肪体重を見れば十分だったりします。

## その他参考（csv読み込み等）

- [pandasでよく使う文法まとめ - @okadate@Qiita](https://qiita.com/okadate/items/7b9620a5e64b4e906c42)

- [今回のソースコード全文 - urahito@GitHub](https://github.com/urahito/python_proj/blob/master/csv/QSAccess.py)