【Python, Google Drive】体重管理&解析アプリを作ろう4 ~解析(グラフ)~

前回記事では、Pythonをベースに、DockerfileとGoogle DriveおよびStreamlitを用いた体重管理及び体重トレンド解析を実装する自分だけのWebアプリを作成するため、登録フォーマットの原型を作成しました。

本アプリの体重アプリの特徴は以下です。

  • すべて無料で構築可能
  • HTML/CSSの知識不要
  • ご自身でアプリのカスタマイズが可能
  • 短時間で実装可能
  • 統計学知識不要

以上のように、誰でも取り掛かりやすい内容となっています。それでは早速やっていきましょう。

1. 解析

今回は、前回で作成した体重データ表を用いて、データを解析していきます。使用するデータは以下のデータフレームを例とします。

図1 本記事で使用するデータ例

まずは、 データ型を 整え、必要な特徴量を作成する”convert_df”関数を作成します。以下のコードを確認してください。”Weight [kg]”と”Fat [%]”はfloat型、それ以外はint型にします。

def convert_df(df, start_date):
    df = df.astype(
        {'Weight [kg]': 'float',
         'Fat [%]': 'float',
         'Breakfast': 'int', 
         'Lunch': 'int',
         'Dinner': 'int',
         'Running': 'int',
         'Muscle': 'int',
         'Sports': 'int'}
         )

さて、使用するデータ範囲を日付で選択します。以下のコードを確認してください。”Date”カラムをパンダスのdatetime型に変更し、引数の”start_date”でデータを抽出します。ここでは、2022年1月1日以降のデータを抽出します。

from datetime import datetime

def convert_df(df, start_date):
    """
    中略
    """
    df['Date'] = pd.to_datetime(df['Date'])
    df = df[df['Date']>=start_date]

あとは、必要な特徴量を算出しておきます。今回は

  • 前回との体重差、初回との体重差
  • 前回との体脂肪率差、初回との体脂肪率差
  • 前回とのLBM(除脂肪体重)差、初回(start_date)とのLBM差
  • 前回との脂肪量差と初回との脂肪量差

を特徴量としました。以下のコードをご確認ください。

def convert_df(df, start_date):
    """
    中略
    """
    df["Weight [kg]"] = df["Weight [kg]"].round(1)
    df["Fat [%]"] = df["Fat [%]"].round(1)
    df["Diff-Weight(Previous)"] = df["Weight [kg]"].diff().fillna(0)
    df["Diff-Weight(Basic)"] = (df["Weight [kg]"] - df["Weight [kg]"][0])
    df["Diff-Fat(Previous)"] = df["Fat [%]"].diff().fillna(0)
    df["Diff-Fat(Basic)"] = (df["Fat [%]"] - df["Fat [%]"][0])
    df["LBM [kg]"] = (df["Weight [kg]"] * (100 - df["Fat [%]"]) / 100)
    df["LBM [kg](Previous)"] = df["LBM [kg]"].diff().fillna(0)
    df["LBM [kg](Basic)"] = (df["LBM [kg]"] - df["LBM [kg]"][0])
    df["Fat [kg]"] = (df["Weight [kg]"] * df["Fat [%]"] / 100)
    df["Fat [kg](Previous)"] = df["Fat [kg]"].diff().fillna(0)
    df["Fat [kg](Basic)"] = (df["Fat [kg]"] - df["Fat [kg]"][0])
    return df

start_date = datetime(2022, 1, 1)
df = convert_df(df, start_date)

これでデータ作成は完了です。他に導入したい特徴量があれば、その都度、この関数に追加してみてください。

2. グラフ解析(体重と体脂肪率)

続いて、体重と体脂肪率のトレンドが見やすいようにグラフを作成します。こちらはお好みでグラフをご変更ください。以下は1軸目の体重データ、2軸目に体脂肪率データを表示するコードとなります。

import matplotlib.pyplot as plt
import matplotlib.dates as mdates


def show_data_weight(df, figsize=(12, 12), font=20):
    ymin1 = df['Weight [kg]'].min() - 5
    ymax1 = df['Weight [kg]'].max() + 1
    ymin2 = df['Fat [%]'].min() - 1
    ymax2 = df['Fat [%]'].max() + 0.5

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    ax.set_title('Weight [kg] VS Fat [%]', fontsize=font)
    
    """ 1軸目 """
    ax.bar(df['Date'], df['Weight [kg]'])
    ax.set_ylim(ymin1, ymax1)
    ax.set_ylabel("Weight [kg]", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)

    """ 2軸目 """
    ax0 = ax.twinx()
    ax0.plot(df['Date'], df['Fat [%]'], marker="o", ms=5, c='indianred')
    ax0.set_ylim(ymin2, ymax2)
    ax0.set_ylabel("Fat [%]", color='red', fontsize=font)
    ax0.grid(False)
    ax0.tick_params(axis='y', colors='red')
    ax0.spines['left'].set_color('blue')
    ax0.spines['right'].set_color('red')

    """ 日付表示フォーマット変更用 """
    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()

show_data_weight(df, figsize=(12, 6), font=15)

上記のコードを実行すると、以下のようなグラフが作成されます。

図2 体重と体脂肪率のグラフ

続いて、体脂肪量の増減を初回値と前回値の2つの側面から確認します。以下のコードをご確認ください。1軸目は、体脂肪率量の増減値において、前回値との差を表示します。 2軸目は、体脂肪率量の増減値において、初期値(Start_dateの日付)との差を表示します。

def show_data_fat_diff(df, figsize=(20, 20), font=20):
    ymin = df['Fat [kg](Basic)'].min() - 1
    ymax = 1.5

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    ax.set_title('Diff-Fat [kg] Previous VS Basic', fontsize=font)

  """ 1軸目 """
    ax.bar(df['Date'], df['Fat [kg](Previous)'])
    ax.set_ylim(ymin, ymax)
    ax.set_ylabel("Diff-Fat [kg](Previous)", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)

    """ 2軸目 """
    ax1 = ax.twinx()
    ax1.plot(df['Date'], df['Fat [kg](Basic)'], marker="o", ms=5, c='indianred')
    ax1.set_ylim(ymin, ymax)
    ax1.set_ylabel("Diff-Fat [kg](Basic)", color='red', fontsize=font)
    ax1.grid(False)
    ax1.tick_params(axis='y', colors='red')
    ax1.spines['left'].set_color('blue')
    ax1.spines['right'].set_color('red')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()

show_data_fat_diff(df, figsize=(12, 6), font=20)

上記コードを実行すると、図3のようなグラフが作成されます。体脂肪量の増減を可視化しておくと、体重管理の進捗が良いかどうか確認しやすいですね。

図3 体脂肪量の増減グラフ

最後に、体脂肪量と除脂肪量の体重割合をグラフ化します。以下のコードをご参考ください。

1軸目は 体脂肪量と除脂肪量 の合計つまり体重、2軸目は体脂肪率を表示します。

def show_data_fat_lbm(df, figsize=(20, 20), font=20):
    ymin1 = 50
    ymax1 = df['Weight [kg]'].max() + 1
    ymin2 = df['Fat [%]'].min() - 1
    ymax2 = df['Fat [%]'].max() + 1

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    df_data = df[['LBM [kg]', 'Fat [kg]']]
    ax.set_title('LBM [kg] VS Fat [kg]', fontsize=font)
    
    """ 1軸目 """
    ax.bar(df['Date'], df_data.iloc[:, 0])
    ax.bar(df['Date'], df_data.iloc[:, 1], bottom=df_data.iloc[:, 0])
    ax.set_ylim(ymin1, ymax1)
    ax.set_ylabel("LBM [kg] + Fat [kg]", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)
    
    """ 2軸目 """
    ax2 = ax.twinx()
    ax2.plot(df['Date'], df['Fat [%]'], marker="o", ms=5, c='black')
    ax2.set_ylim(ymin2, ymax2)
    ax2.set_ylabel("Fat [%]", color='red', fontsize=font)
    ax2.grid(False)
    ax2.tick_params(axis='y', colors='red')
    ax2.spines['left'].set_color('blue')
    ax2.spines['right'].set_color('red')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()

show_data_fat_lbm(df, figsize=(12, 6), font=15)

上記コードを実行すると、図4のようにLBMとFatの増減を確認できるので、体重変化の詳細を確認できます。

図4 体重変移(LBMとFat)

こちらで基本的なグラフ化は以上となります。ぜひ、ご自身で特徴量を増やして、有益な情報をグラフ化してみてください。

3. まとめコード

from datetime import datetime
import time
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates


def convert_df(df, start_date):
    df = df.astype(
        {'Weight [kg]': 'float16',
         'Fat [%]': 'float16',
         'Fasting': 'int',
         'Breakfast': 'int', 
         'Lunch': 'int',
         'Dinner': 'int',
         'Running': 'int',
         'Muscle': 'int',
         'Sports': 'int'}
         )
    df['Date'] = pd.to_datetime(df['Date'])
    df = df[df['Date']>=start_date]
    df["Weight [kg]"] = df["Weight [kg]"].round(1)
    df["Fat [%]"] = df["Fat [%]"].round(1)
    df["Diff-Weight(Previous)"] = df["Weight [kg]"].diff().fillna(0)
    df["Diff-Weight(Basic)"] = (df["Weight [kg]"] - df["Weight [kg]"][0])
    df["Diff-Fat(Previous)"] = df["Fat [%]"].diff().fillna(0)
    df["Diff-Fat(Basic)"] = (df["Fat [%]"] - df["Fat [%]"][0])
    df["LBM [kg]"] = (df["Weight [kg]"] * (100 - df["Fat [%]"]) / 100)
    df["LBM [kg](Previous)"] = df["LBM [kg]"].diff().fillna(0)
    df["LBM [kg](Basic)"] = (df["LBM [kg]"] - df["LBM [kg]"][0])
    df["Fat [kg]"] = (df["Weight [kg]"] * df["Fat [%]"] / 100)
    df["Fat [kg](Previous)"] = df["Fat [kg]"].diff().fillna(0)
    df["Fat [kg](Basic)"] = (df["Fat [kg]"] - df["Fat [kg]"][0])
    return df


def show_data_weight(df, figsize=(12, 12), font=20):
    ymin1 = df['Weight [kg]'].min() - 5
    ymax1 = df['Weight [kg]'].max() + 1
    ymin2 = df['Fat [%]'].min() - 1
    ymax2 = df['Fat [%]'].max() + 0.5

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    ax.set_title('Weight [kg] VS Fat [%]', fontsize=font)

    ax.bar(df['Date'], df['Weight [kg]'])
    ax.set_ylim(ymin1, ymax1)
    ax.set_ylabel("Weight [kg]", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)

    ax0 = ax.twinx()
    ax0.plot(df['Date'], df['Fat [%]'], marker="o", ms=5, c='indianred')
    ax0.set_ylim(ymin2, ymax2)
    ax0.set_ylabel("Fat [%]", color='red', fontsize=font)
    ax0.grid(False)
    ax0.tick_params(axis='y', colors='red')
    ax0.spines['left'].set_color('blue')
    ax0.spines['right'].set_color('red')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()


def show_data_fat_diff(df, figsize=(20, 20), font=20):
    ymin = df['Fat [kg](Basic)'].min() - 1
    ymax = 1.5

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    ax.set_title('Diff-Fat [kg] Previous VS Basic', fontsize=font)

    ax.bar(df['Date'], df['Fat [kg](Previous)'])
    ax.set_ylim(ymin, ymax)
    ax.set_ylabel("Diff-Fat [kg](Previous)", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)

    ax1 = ax.twinx()
    ax1.plot(df['Date'], df['Fat [kg](Basic)'], marker="o", ms=5, c='indianred')
    ax1.set_ylim(ymin, ymax)
    ax1.set_ylabel("Diff-Fat [kg](Basic)", color='red', fontsize=font)
    ax1.grid(False)
    ax1.tick_params(axis='y', colors='red')
    ax1.spines['left'].set_color('blue')
    ax1.spines['right'].set_color('red')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()


def show_data_fat_lbm(df, figsize=(20, 20), font=20):
    ymin1 = 50
    ymax1 = df['Weight [kg]'].max() + 1
    ymin2 = df['Fat [%]'].min() - 1
    ymax2 = df['Fat [%]'].max() + 1

    fig, ax = plt.subplots(1, 1, figsize=figsize)
    df_data = df[['LBM [kg]', 'Fat [kg]']]
    ax.set_title('LBM [kg] VS Fat [kg]', fontsize=font)

    ax.bar(df['Date'], df_data.iloc[:, 0])
    ax.bar(df['Date'], df_data.iloc[:, 1], bottom=df_data.iloc[:, 0])
    ax.set_ylim(ymin1, ymax1)
    ax.set_ylabel("LBM [kg] + Fat [kg]", color='blue', fontsize=font)
    ax.grid(True)
    ax.tick_params(axis='y', colors='blue')
    ax.set_xticklabels(df['Date'], rotation=90)

    ax2 = ax.twinx()
    ax2.plot(df['Date'], df['Fat [%]'], marker="o", ms=5, c='black')
    ax2.set_ylim(ymin2, ymax2)
    ax2.set_ylabel("Fat [%]", color='red', fontsize=font)
    ax2.grid(False)
    ax2.tick_params(axis='y', colors='red')
    ax2.spines['left'].set_color('blue')
    ax2.spines['right'].set_color('red')

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
    plt.rcParams["font.size"] = font
    plt.show()


start_date = datetime(2022, 1, 1)
show_data_weight(df, figsize=(12, 6), font=15)
show_data_fat_diff(df, figsize=(12, 6), font=15)
show_data_fat_lbm(df, figsize=(12, 6), font=15)

お疲れさまでした。次回は、簡易解析したデータをグラフ化していきます。

4. 関連記事

随時更新中です。公開次第、リンクを貼り付けていきます。

Baran

それでは、よいPythonライフを!

Baran

以下の記事も書いています。よかったらご覧ください。

Baran

Twitterもやってまーす。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US

Baran-gizagiza
経歴:浪人→理系大学院卒業→大手製造業に就職(技術職)→アメリカ赴任中 仕事は、研究・設計など上流工程の仕事に携わっています。企業勤務を継続しながら、新しいことにチャレンジしたいと思い、ブログを下記はじめました。 このブログでは、趣味である 筋トレ(健康、ダイエット) AIとデータ(高校数学、プログラミング) 読書(主に自己啓発系) を中心に、人生経験やおすすめ情報の発信しています。