誰にも頼まれていないデータ分析
ライフスタイル

食事の最適化:最小限の食材で1日の必要栄養素を満たすには

  • 食事
  • 数理最適化
  • Python

この記事で分かること

  • 1日に必要な栄養素を満たす食事を、数学で作れるのか
  • 数理最適化すると、どんな食材が選ばれるのか
  • 「栄養を満たす」と「現実的に食べられる」は両立するのか

1.「最強の食事」を数学で作ってみたい

毎日、何を食べるか考えるのは意外と面倒です。

しかも、

  • タンパク質は足りているかな?
  • 野菜はちゃんと食べたかな?
  • ビタミンやミネラルは?

と考え始めると、なかなか大変です。

そこで、ふと思いました。

1日に必要な栄養素を全部満たしながら、できるだけ少ない量の食材で済む食事を、数学で作ることはできないだろうか?

今回はこれを、数理最適化を使って計算してみます。条件は 20 代男性としました。

2.まずはデータを集める

今回必要なのは、大きく 2 種類のデータです。

① 1日に必要な栄養素

厚生労働省の「日本人の食事摂取基準」を使います。ここから、20 代男性が 1 日に必要な栄養素の量を設定します。

日本人の食事摂取基準|厚生労働省健康の保持・増進のために参照する、エネルギーと栄養素の摂取量の基準。年齢・性別ごとに推奨量や耐容上限量が定められています。mhlw.go.jp
たんぱく質の食事摂取基準表。性別・年齢別の推定平均必要量と推奨量が並ぶ
たんぱく質の基準。18〜29歳男性の推奨量は65g

栄養素によっては、「これ以上摂ってはいけない」という上限も決められています。ビタミン A がその例です。

ビタミンAの食事摂取基準表。耐容上限量の列がある
ビタミンAには耐容上限量がある。18〜29歳男性は2,700μgRAE

② 食材ごとの栄養素

次に必要なのは、「この食材を 100g 食べると、どれくらいの栄養素を摂れるのか?」というデータです。

そこで、文部科学省の「日本食品標準成分表2020年版(八訂)」を使います。2,478 品目の栄養素が収録されています。

日本食品標準成分表・資源に関する取組|文部科学省食品に含まれる栄養成分の基礎的データ集。戦後から70年以上にわたって改訂・公表されており、栄養指導などに利用されています。mext.go.jp
日本食品標準成分表のスプレッドシート。食品ごとにエネルギー・たんぱく質・脂質・無機質などが並ぶ
食品標準成分表。1行が1品目で、列が各栄養素にあたる

3.では、数学に「最強の食事」を作ってもらおう

ここで使うのが数理最適化です。

難しそうな名前ですが、考え方はシンプルです。

「これだけは守ってね」という条件の中で、一番いい答えを探す方法。

3次関数のグラフ。0から2の区間での最大値を探すことを示している
決められた範囲の中で、最大値・最小値を探すのが数理最適化

今回なら、条件はこうなります。

  1. 1栄養素は必要量以上にする。
  2. 2上限がある栄養素は、上限を超えない。
  3. 3そのうえで、食材の合計量をできるだけ少なくする。

つまり「栄養は全部足りている。でも、食べる量はできるだけ少ない」という食事を探します。

4.まず普通に計算してみる

Python の数理最適化ライブラリ「PuLP」を使って計算します。

食材 1 種類あたりの摂取量には、上限 200g を設定しました。1 つの食材だけを大量に食べる答えが出ないようにするためです。

各食材の摂取量が0以上200以下であることを示す式
1食材あたり200gまでという制約

そして、食材の合計重量が最も小さくなる組み合わせを探します。

さあ、どんな食事が出てくるでしょうか。

5.……結果がおかしい

CBCソルバーの出力。Optimal - objective value 565.04392 と表示されている
合計565.04gで必要栄養素をすべて満たす解が見つかった

計算結果は、565g。

一見すると「たった 565g で 1 日の必要栄養素を満たせるの?」と驚きます。

ところが、中身を見てみると……

1回目の計算結果(上位のみ)
食材摂取量
角砂糖200.0g
ひまわり油60.3g
りょくとう58.8g
ごま46.6g
らっかせい39.8g
まいたけ39.6g
その他

角砂糖200g。

さらに、ひまわり油 60.3g。

これは……食事と呼んでいいのでしょうか。

6.なぜ「角砂糖200g」が選ばれた?

もちろん、数学が間違えたわけではありません。

今回の目的は「食材の合計重量を最小にする」ことでした。そのため、少ない重量で多くのエネルギーを確保できる食品が有利になります。

「健康的でおいしい食事」を探したわけではなく、「設定した条件を満たしながら重量を最小にする組み合わせ」を探した結果、角砂糖が選ばれた。

数学的には正解。でも、人間にはかなり厳しい。

7.数学だけでは「食べられる食事」にならない

ここで問題が分かりました。

「栄養素を満たす」という条件だけでは、「現実的に食べられるか?」という条件が抜けています。

では、1 つの食材を 20g までに制限すればいいのでしょうか。

それだと、今度はご飯のように 200g 程度食べてもおかしくない食品まで、20g しか使えなくなってしまいます。

食材ごとに「この食品なら、このくらいの量までなら現実的」というデータがあれば理想的です。しかし、そのようなデータは見つけられませんでした。

そこで今回は、別の方法を取ります。

8.ここからは人間の判断を入れる

「明らかに現実的ではない食材が選ばれたら、その食材を候補から外して、もう一度計算する」

実際に、調味料系、油脂類、非常に特殊な食材などを除外して再計算しています。

つまりここからは、数学だけでなく、人間の感覚も少し入ります。

そして、もう一度「最強の食事」を計算します。

9.再計算した結果がこちら

2回目の計算結果(合計 約889g)
食材摂取量
小麦粉200.00g
いんげん豆200.00g
レンズ豆185.68g
モロヘイヤ72.76g
まいたけ(油いため)67.88g
らっかせい48.67g
ドライマンゴー36.04g
アーモンド30.00g
まいたけ(乾)16.37g
なつめやし15.63g
チアシード10.00g
牛レバー4.53g
アセロラ1.44g
刻み昆布0.05g

……やはり普通の献立とはかなり違います。

でも、最初の「角砂糖200g」よりは、かなり食事らしくなりました。

10.本当に必要な栄養素は全部足りている?

では、この食事で栄養素をどれだけ摂れるのでしょうか。

2回目の計算結果で摂れる栄養素(一部)
栄養素摂取量
カロリー2,650kcal
タンパク質136.0g
脂質58.9g
炭水化物457.4g
食物繊維103.3g
ビタミンC100.0mg
カルシウム800.0mg
34.0mg

必要量を下回らないようにしつつ、上限が設定されている栄養素については、上限を超えない結果になっています。

ただし、すべてが必要量ぴったりというわけではありません。葉酸は 784.7、カリウムは 7,050.3、モリブデンは 600.0 と、必要量を大きく上回っている栄養素もあります。

11.「最強の食事」は、本当に最強なのか?

今回分かったのは、少し意外なことでした。

数学的に「栄養を満たす」ことと、人間にとって「良い食事」であることは、同じではありません。

最初の計算では、角砂糖200gという結果が出ました。これは計算としては間違っていません。

ただ、「何を最小化するのか」によって、答えは大きく変わります。

今回は「食材の合計重量」を最小化しました。もし食費を最小化するなら、答えは変わるでしょう。調理時間を最小化するなら、さらに違う答えになるはずです。

つまり「最強の食事」というものは、何を最強と定義するかによって変わります。

12.🔍 ちなみに、どうやって調べた?

ここからは、今回の分析方法について少し詳しく説明します。

「どうやってこの食事を計算したの?」と気になった方はぜひどうぞ。

分析方法をくわしく見る

使用したデータ

本文でも触れたとおり、2 つのデータを組み合わせています。

データ用途規模
日本人の食事摂取基準(厚生労働省)1日に必要な栄養素の基準値20代男性の数値を使用
日本食品標準成分表2020年版 八訂(文部科学省)各食品に含まれる栄養素2,478品目

なぜこの2つのデータを使った?

今回の問題は、「必要な栄養素」と「食品に含まれる栄養素」を組み合わせることで解けます。

そのため、必要量を厚生労働省から、食品の栄養成分を文部科学省から取り、2 つを突き合わせています。

分析の流れ

  1. 120代男性の1日に必要な栄養素量を用意する。
  2. 2各食品の栄養成分データを用意する。
  3. 3各食品の摂取量を変数として設定する。
  4. 4必要な栄養素を下回らないように制約を設定する。
  5. 5上限量がある栄養素は、上限を超えないように制約を設定する。
  6. 6各食品の摂取量には0〜200gの範囲を設定する。
  7. 7食材の合計摂取量が最小になる組み合わせをPuLPで求める。
  8. 8非現実的な食品が含まれた場合、その食品を除外して再計算する。

制約式と目的関数

栄養素ごとに「摂取量が必要量以上になる」という制約を立てます。制約式は栄養素の数だけ並びます。

制約式と目的関数を示した数式。栄養素ごとの摂取量が推奨量以上になる制約が並ぶ
制約式は栄養素の数だけ並ぶ

上限量のある栄養素については、逆向きの制約も加えます。

ビタミンAの摂取量が上限以下になることを示す制約式
上限のある栄養素には、超えないための制約も入れる

最小化したのは、各食材の摂取量の合計です。つまり「できるだけ少ない重量で必要な栄養素を満たす」という問題として設定しています。

そのため、これは「食材の種類数を最小化する問題」ではありません。

使用したコード

Python の PuLP を使って実装しています。

from pulp import *

problem = LpProblem(sense=LpMinimize)

P = df.index.to_list()

x = LpVariable.dicts(
    'x',
    P,
    cat='Continuous',
    lowBound=0,
    upBound=200
)

lowBound=0 によって摂取量の下限を 0g にし、upBound=200 によって 1 食品あたりの上限を 200g に設定しています。

そのうえで各栄養素について必要量や上限量の制約を追加し、最後に食品の合計量を最小化します。

problem += lpSum([1*x[p] for p in P])

食品の除外について

最初の結果では、角砂糖や油など、現実の食事としては扱いにくい食品が選ばれました。

そこで、食品名に含まれるキーワードなどを利用し、次のような食品を手動で除外しています。

  • 調味料系
  • 油脂類
  • 非常に特殊な食品
  • 食べることを想定しにくい食品

これは完全に自動化された判断ではなく、分析者による人間の判断が入っている部分です。

分析上の注意点

今回の結果は「これを食べれば健康になれる理想の献立」ではありません。あくまで、設定した栄養基準・食品データ・制約条件のもとで、食材の合計量を最小化した結果です。

特に、次の点は最適化していません。

  • 食材の味
  • 調理方法
  • 食べやすさ
  • 食事の満足感
  • 食材価格
  • 食材同士の相性
  • 食事の継続しやすさ

13.まとめ

  • 栄養素の必要量と食品成分のデータを使えば、「栄養を満たす食事」を数理最適化できる
  • 非現実的な食品を除外して再計算すると、小麦粉・豆類・モロヘイヤなどを中心とした組み合わせになった
  • 「栄養を満たす」と「おいしく、現実的に食べられる」は別問題だった
  • 何を「最適」とするかによって、数学が導き出す食事は大きく変わる

14.次に調べたいこと

今回の「最強の食事」は、まだまだ改良できそうです。例えば、

  • 食費を最小化したら、どんな食事になる?
  • 調理時間を最小化したらどうなる?
  • 20代女性や40代男性では結果が変わる?
  • 「おいしさ」や「食べやすさ」まで条件に入れたらどうなる?
  • 最適化された食材を、実際の料理にするとどんな献立になる?

このあたりまで条件を追加していくと、「数学が考えた最強の食事」から「人間が本当に食べたい最強の食事」へ進化させられそうです。

関連する記事