はじめに
どうも、マッチョです。💪
世の中では「鶏むね肉が最強」なんて言われていますが、
それが本当だなんてちゃんと確かめたことはないですよね。
なら、ちゃんとデータで決着つけようっちゅう話。
というわけで今回は、
厚労省の「日本食品標準成分表」のデータを使って、
どの食材が最も筋トレ向きなのか?
今回は、筋肉が歓喜する食材ランキングをデータで検証していこうと思います。。
📊 分析方法
- 使用データ:厚労省「日本食品標準成分表(八訂)」
https://www.mext.go.jp/content/20260327-mxt_kagsei-mext-000029402_02.xlsx - 対象項目:エネルギー、たんぱく質、脂質、炭水化物
- スコアリング:各食品の3大栄養素比率を合計100%とし、PFCバランスの理想比(2:2:1)との距離をスコア化
- スコアの基準:スコアが小さいほど「理想比に近い(優秀)」と判定
- 同点の場合は:カロリーが低い順に並べてランキング
- 外条件:エネルギー(kcal)が 0 の食品(水、お茶など)や調味料は除外
実行するソースコード
import numpy as np
import pandas as pd
FILE_PATH = "/content/drive/MyDrive/Colab Notebooks/Qiita/筋肉食材ランキング/20260327-mxt_kagsei-mext-000029402_02.xlsx"
def create_muscle_pfc_ranking(
file_path: str,
target_pfc: tuple = (2, 2, 1),
exclude_non_food: bool = True,
min_protein_g: float = 8.0,
):
# 1. シートの読み込み
raw_df = pd.read_excel(file_path, sheet_name="表全体", header=None)
# 2. 成分識別子行の特定
id_row_idx = None
for idx, row in raw_df.head(15).iterrows():
row_str_list = (
row.astype(str)
.str.replace(r"\s+", "", regex=True)
.str.upper()
.tolist()
)
if "ENERC_KCAL" in row_str_list:
id_row_idx = idx
break
if id_row_idx is None:
raise ValueError("成分識別子が見つかりませんでした。")
identifiers = (
raw_df.iloc[id_row_idx]
.astype(str)
.str.replace(r"\s+", "", regex=True)
.str.upper()
.tolist()
)
# 3. 列インデックスの特定
col_indices = {}
for col_idx in range(raw_df.shape[1]):
column_str = "".join(raw_df.iloc[0 : id_row_idx, col_idx].astype(str))
column_str_clean = column_str.replace(" ", "").replace(" ", "")
if "食品名" in column_str_clean:
col_indices["食品名"] = col_idx
break
def find_col_index(target_ids):
for t_id in target_ids:
if t_id in identifiers:
return identifiers.index(t_id)
return None
col_indices["エネルギー"] = find_col_index(["ENERC_KCAL"])
col_indices["たんぱく質"] = find_col_index(["PROT-", "PROT"])
col_indices["脂質"] = find_col_index(["FAT-", "FAT"])
col_indices["炭水化物"] = find_col_index(["CHO-", "CHO", "CHOAVL"])
# 4. データの抽出とクレンジング
data_start_idx = id_row_idx + 1
clean_df = pd.DataFrame()
clean_df["食品名"] = (
raw_df.iloc[data_start_idx:, col_indices["食品名"]]
.astype(str)
.str.strip()
)
clean_df["エネルギー(kcal)"] = raw_df.iloc[
data_start_idx:, col_indices["エネルギー"]
]
clean_df["たんぱく質(g)"] = raw_df.iloc[
data_start_idx:, col_indices["たんぱく質"]
]
clean_df["脂質(g)"] = raw_df.iloc[data_start_idx:, col_indices["脂質"]]
clean_df["炭水化物(g)"] = raw_df.iloc[
data_start_idx:, col_indices["炭水化物"]
]
clean_df = clean_df[
clean_df["食品名"].notna()
& (clean_df["食品名"] != "")
& (~clean_df["食品名"].str.contains("単位|成分識別子|食品名"))
]
calc_cols = ["エネルギー(kcal)", "たんぱく質(g)", "脂質(g)", "炭水化物(g)"]
for col in calc_cols:
clean_df[col] = pd.to_numeric(
clean_df[col]
.astype(str)
.str.replace(r"[^\d\.]", "", regex=True),
errors="coerce",
).fillna(0)
# 調味料などの除外
if exclude_non_food:
exclude_keywords = [
"みそ",
"味噌",
"しょうゆ",
"ソース",
"ドレッシング",
"カレーパウダー",
"ジャム",
"マヨネーズ",
"だし",
"スープ",
"乾燥",
"こしょう",
"プレミックス",
]
pattern = "|".join(exclude_keywords)
clean_df = clean_df[~clean_df["食品名"].str.contains(pattern)]
# たんぱく質下限による足切り
clean_df = clean_df[clean_df["たんぱく質(g)"] >= min_protein_g]
# 5. PFCカロリー比率の計算
p_cal = clean_df["たんぱく質(g)"] * 4
f_cal = clean_df["脂質(g)"] * 9
c_cal = clean_df["炭水化物(g)"] * 4
total_cal = p_cal + f_cal + c_cal
total_cal = total_cal.replace(0, np.nan)
clean_df["pct_p_cal"] = p_cal / total_cal
clean_df["pct_f_cal"] = f_cal / total_cal
clean_df["pct_c_cal"] = c_cal / total_cal
target_sum = sum(target_pfc)
ideal_p = target_pfc[0] / target_sum
ideal_f = target_pfc[1] / target_sum
ideal_c = target_pfc[2] / target_sum
# 6. ペナルティスコアの計算
p_penalty = np.maximum(0, ideal_p - clean_df["pct_p_cal"])
f_penalty = np.maximum(0, clean_df["pct_f_cal"] - ideal_f)
c_penalty = np.maximum(0, clean_df["pct_c_cal"] - ideal_c)
clean_df["score"] = np.sqrt(
p_penalty**2 + f_penalty**2 + c_penalty**2
)
clean_df["score"] = clean_df["score"].fillna(np.inf)
# 7. ランキングのソートと確定
ranked_df = clean_df.sort_values(
by=["score", "たんぱく質(g)", "エネルギー(kcal)"],
ascending=[True, False, True],
).reset_index(drop=True)
ranked_df["ranking"] = ranked_df.index + 1
# 8. 表記の丸め処理
for col in ["pct_p_cal", "pct_f_cal", "pct_c_cal"]:
ranked_df[col] = (ranked_df[col] * 100).round(1).astype(str) + "%"
ranked_df["score"] = ranked_df["score"].round(4)
return ranked_df
# ランキングの実行
try:
result_df = create_muscle_pfc_ranking(
FILE_PATH, target_pfc=(2, 2, 1), exclude_non_food=True, min_protein_g=8.0
)
print("\n--- 筋肉食材!PFCカロリーバランス(2:2:1) パターンAランキング TOP 30 ---")
display(
result_df[
[
"ranking",
"食品名",
"エネルギー(kcal)",
"score",
"たんぱく質(g)",
"脂質(g)",
"炭水化物(g)",
"pct_p_cal",
"pct_f_cal",
"pct_c_cal",
]
].head(20)
)
except Exception as e:
print(f"エラーが発生しました: {e}")
ソースコードの説明です。
1. 成分標準成分表の自動パース(前処理)
Excel(「表全体」シート)から、成分識別子(ENERC_KCAL や PROT など)の行を検出し、必要な列インデックス(食品名・カロリー・3大栄養素)を特定してクレンジングします。
2. ノイズデータの除外
エネルギーが 0 の食品や、日常の摂取量が少なくデータ上の数値が跳ねやすい「調味料・スープ」などをキーワードで除外。さらに、たんぱく質が極端に少ない食材を足切りします。
3. カロリーベースのPFC比率と「理想との距離」の計算
各栄養素をグラム数からカロリーに換算(P=4, F=9, C=4)し、その合計に対する各自の割合を算出。目標とする理想比(2:2:1 = 40%:40%:20%)からの乖離度をユークリッド距離(ベクトルの長さ)を用いてスコア化します。
4. 筋肉仕様のソートによるランキング確定
スコアが小さい順(=理想比に近い順)を最優先し、同点の場合は「たんぱく質含有量(g)が多い順」、さらに同点なら「総エネルギー(kcal)が低い順」の3段階でソートをかけます。
ということで、結果を見てみましょう。
💪 結果(TOP20)💪
| $\text{順位}$ | $\text{食品名}$ | $\text{kcal}$ | $\text{score}$ | $\text{P(g)}$ | $\text{F(g)}$ | $\text{C(g)}$ | $\text{P%}$ | $\text{F%}$ | $\text{C%}$ |
|---|---|---|---|---|---|---|---|---|---|
| $\text{1}$ | $\text{<畜肉類> ぶた [その他] ゼラチン}$ | $\text{347}$ | $\text{0.0}$ | $\text{87.6}$ | $\text{0.3}$ | $\text{0.0}$ | $\text{99.2%}$ | $\text{0.8%}$ | $\text{0.0%}$ |
| $\text{2}$ | $\text{<牛乳及び乳製品> (その他) カゼイン}$ | $\text{358}$ | $\text{0.0}$ | $\text{86.2}$ | $\text{1.5}$ | $\text{0.0}$ | $\text{96.2%}$ | $\text{3.8%}$ | $\text{0.0%}$ |
| $\text{3}$ | $\text{<魚類> (さめ類) ふかひれ}$ | $\text{344}$ | $\text{0.0}$ | $\text{83.9}$ | $\text{1.6}$ | $\text{0.0}$ | $\text{95.9%}$ | $\text{4.1%}$ | $\text{0.0%}$ |
| $\text{4}$ | $\text{<魚類> とびうお 煮干し}$ | $\text{325}$ | $\text{0.0}$ | $\text{80.0}$ | $\text{2.2}$ | $\text{0.1}$ | $\text{94.1%}$ | $\text{5.8%}$ | $\text{0.1%}$ |
| $\text{5}$ | $\text{だいず [その他] 大豆たんぱく 分離大豆たんぱく 塩分無調整タイプ}$ | $\text{335}$ | $\text{0.0}$ | $\text{79.1}$ | $\text{3.0}$ | $\text{1.0}$ | $\text{91.1%}$ | $\text{7.8%}$ | $\text{1.2%}$ |
| $\text{6}$ | $\text{だいず [その他] 大豆たんぱく 分離大豆たんぱく 塩分調整タイプ}$ | $\text{335}$ | $\text{0.0}$ | $\text{79.1}$ | $\text{3.0}$ | $\text{1.0}$ | $\text{91.1%}$ | $\text{7.8%}$ | $\text{1.2%}$ |
| $\text{7}$ | $\text{<魚類> (さけ・ます類) しろさけ サケ節 削り節}$ | $\text{346}$ | $\text{0.0}$ | $\text{77.4}$ | $\text{3.4}$ | $\text{0.2}$ | $\text{90.8%}$ | $\text{9.0%}$ | $\text{0.2%}$ |
| $\text{8}$ | $\text{<魚類> (かつお類) 加工品 かつお節}$ | $\text{332}$ | $\text{0.0}$ | $\text{77.1}$ | $\text{2.9}$ | $\text{0.7}$ | $\text{91.4%}$ | $\text{7.7%}$ | $\text{0.8%}$ |
| $\text{9}$ | $\text{<魚類> (かつお類) 加工品 削り節}$ | $\text{327}$ | $\text{0.0}$ | $\text{75.7}$ | $\text{3.2}$ | $\text{0.4}$ | $\text{90.9%}$ | $\text{8.6%}$ | $\mathbf{0.5%}$ |
| $\text{10}$ | $\text{<魚類> (いわし類) たたみいわし}$ | $\text{348}$ | $\text{0.0}$ | $\text{75.1}$ | $\text{5.6}$ | $\text{0.6}$ | $\text{85.1%}$ | $\text{14.3%}$ | $\text{0.7%}$ |
💡 分析結果と考察
1. プロテイン原材料が上位を独占
ゼラチン?カゼイン?なんのこっちゃ分からないですが、どうやら市販されているプロテインパウダーの原材料に使われているものらしいです。そりゃ1、2位になりますね。
2. 乾燥・加工魚介類のポテンシャル
水分を徹底的に飛ばす(乾燥させる)ことで、100gあたりの栄養密度を限界まで高めてるってことですかね。
💡 考察
1、2位はなるべくしてなったと言えますね。魚介系は乾燥してるが故のランクインのため、今回の検証は微妙だったかも、、、と感じでいます。
ちなみに、鶏むね肉(皮なし)は40位、卵は100位以下でした。
まとめ
個人的には3位のフカヒレが意外でした。すごいタンパク質量ですね。栄養面で見ても高級なだけのことはある。
今回は食材の栄養価のみで判定し、食べやすさなどの現実味はなかったため、そこは改善の余地ありと感じました。
では💪