前回記事では、Pythonをベースに、DockerfileとGoogle DriveおよびStreamlitを用いた体重管理及び体重トレンド解析を実装する自分だけのWebアプリを作成するため、登録フォーマットの原型を作成しました。
本アプリの体重アプリの特徴は以下です。
- すべて無料で構築可能
- HTML/CSSの知識不要
- ご自身でアプリのカスタマイズが可能
- 短時間で実装可能
- 統計学知識不要
以上のように、誰でも取り掛かりやすい内容となっています。それでは早速やっていきましょう。
▼ Contents
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つの側面から確認します。以下のコードをご確認ください。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のようなグラフが作成されます。体脂肪量の増減を可視化しておくと、体重管理の進捗が良いかどうか確認しやすいですね。

最後に、体脂肪量と除脂肪量の体重割合をグラフ化します。以下のコードをご参考ください。
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の増減を確認できるので、体重変化の詳細を確認できます。

こちらで基本的なグラフ化は以上となります。ぜひ、ご自身で特徴量を増やして、有益な情報をグラフ化してみてください。
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. 関連記事
随時更新中です。公開次第、リンクを貼り付けていきます。

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

Twitterもやってまーす。
それでは、よいPythonライフを!