Optimal Diets

When I read that I should eat food X because it has a lot of Vitamin Q, I always wonder if you could eat all the foods that someone recommends. This food here because it has a lot of Vitamin A, this other one because it has a ton of Vitamin K, and so on. How do you know that that new food isn’t going to overload your diet in some other dimension, like too much sugar, fat, etc?

Well, let’s see how math can help answer that question.
We are going to look at an optimization method called Linear Programming and see if we can figure out an Optimal Diet.

If you want to follow along and try out some of the programs for yourself, they are available at https://gitlab.com/dgrunberg/optimal-diet.  You will need to download the USDA data separately, links are provided in the README file.

DISCLAIMER: Do not follow any diets proposed below without consulting your doctor.  You’ll probably get sick. Or die of a kale overdose.
Nutrition Data
First we have to start with a source of data.  The USDA has conveniently collected nutritional information on 8,000 foods for us at the website  www.ars.usda.gov.  They provide the data on how much of various nutrients are in a 100g serving of each food.  The data is provided in a text file format that is fairly easy to parse with your favorite programming language.

We have massaged the data into the following form, which will make it easier for us to discuss algorithms:

where \(q_{ij}\) is the amount of nutrient \(j\) that a serving of food \(i\) contains.
Then a diet can be represented by a vector \(x=[x_i]\) where each value is the number of servings of that food that we are consuming (per day). This is what mathematicians call thinking abstractly: we can call a string of numbers \(x\) a diet without a second thought.
Q^T x
represents the vector of nutrients in the diet.
Now one more thing – our diet has certain restrictions. Let’s start with minimums: each nutrient may have a minimum amount that we must consume. So, let \(b\)
be the vector of minimum amounts of each nutrient that we require (assume for the moment that every nutrient has a minimum). Then we can write:
Q^T x \geq b
If only some of the nutrients have minimums, we would only include the rows of Q^T that correspond to them in the equation.

Linear Programming

Linear Programming is an optimization problem (and solution) that looks like:
Find an x that minimizes
c^T x
subject to:
Ax &\leq b\\
x &\geq 0

There are numerous ways to access a Linear Programming algorithm – e.g. MATLAB or Octave. In the code provided with this post, we will be using the scipy package scipy.optimize.linprog. What happens when we try it?
The first attempt I did was to minimize total calories while meeting the RDAs for various nutrients.
The first attempt gave this. It has 1103 calories. You could fill in the rest of your calories with sugar, as there is no maximum on sugar calories.

food  portions  food-description
10062 1.18  Pork chop
11458 10.42 Spinach
01082 16.23 Milk

Looks appetizing, doesn’t it? Well, as you look into the solution, you see that Vitamin D ends up being a problem, which contributes to the large milk dose.
In any case, I decided to switch to making the total calories fixed at 2000. I needed find something else to minimize, so I choose total servings. There some other things that could be interesting, such as price. We would need a database of food prices to proceed there. Maybe a future post.

The first try with 2000 calorie diet gives this:

food portions food-description
11090 0.84 Broccoli, raw
11147 0.02 Chard, swiss, raw
16028 1.66 Beans, kidney, all types, mature seeds, cooked, boiled, without salt
20051 2.90 Rice, white, medium-grain, enriched, cooked
18075 0.22 Bread, whole-wheat, commercially prepared
01128 0.33 Egg, whole, cooked, fried
01082 13.33 Milk, lowfat, fluid, 1% milkfat, with added vitamin A and vitamin D
12062 0.80 Nuts, almonds, blanched
11357 1.00 Potatoes, white, flesh and skin, baked
15121 2.78 Fish, tuna, light, canned in water, drained solids

Seems reasonable, except for all the milk. When I tried to limit the milk servings, the optimizer could find a solution. Here is the result if you temporarily eliminate the Vitamin D requirement:

food portions food-description
11090 0.83 Broccoli, raw
11124 0.89 Carrots, raw
16028 5.76 Beans, kidney, all types, mature seeds, cooked, boiled, without salt
20051 0.53 Rice, white, medium-grain, enriched, cooked
18075 2.08 Bread, whole-wheat, commercially prepared
01270 0.42 Cheese, cheddar, sharp, sliced
15061 2.25 Fish, perch, mixed species, cooked, dry heat
12062 0.71 Nuts, almonds, blanched

Except for all the beans, looks like getting closer to palatable. The problem is that when it tries to replace the milk with tuna, which has Vitamin D also, it runs into the saturated fat limit. Ah, the problems constraints give optimizers.

One more try, then I will let you try things out on your own. On a list of high Vitamin D foods, I found salmon and almond milk. Let’s add those as options and see what we get. Here is the full program output so you can see it for yourself:

food id    portions   food-description
11090          0.85  Broccoli, raw
11124          0.73  Carrots, raw
16028          6.00  Beans, kidney, all types, mature seeds, cooked, boiled, without salt
20051          0.77  Rice, white, medium-grain, enriched, cooked
18075          1.62  Bread, whole-wheat, commercially prepared
01270          0.70  Cheese, cheddar, sharp, sliced
15061          1.39  Fish, perch, mixed species, cooked, dry heat
12062          0.45  Nuts, almonds, blanched
15086          1.15  Fish, salmon, sockeye, cooked, dry heat

Calories by category:
Protein                              676      33.2%
Fat                                  585      28.7%
Carbs, less fiber                    775      38.1%
TOTAL                               2035

nutrient      units       min       max     value name                   major contributor
203 PROCNT        g     50.00      0.00    168.99 Protein              (Beans, kid:    52.0)
204 FAT           g      0.00     65.00     65.00 Total lipid (fat)    (Cheese, ch:    23.8)
205 CHOCDF        g      0.00      0.00    250.74 Carbohydrate, by dif (Beans, kid:   136.9)
208 ENERC_KCAL kcal      0.00      0.00   2228.44 Energy               (Beans, kid:   762.3)
291 FIBTG         g     25.00      0.00     57.11 Fiber, total dietary (Beans, kid:    38.4)
301 CA           mg   1300.00      0.00   1300.00 Calcium, Ca          (Cheese, ch:   501.1)
303 FE           mg     18.00      0.00     23.13 Iron, Fe             (Beans, kid:    13.3)
304 MG           mg    420.00      0.00    645.05 Magnesium, Mg        (Beans, kid:   252.1)
305 P            mg   1250.00      0.00   2532.93 Phosphorus, P        (Beans, kid:   828.3)
306 K            mg   4700.00      0.00   4700.00 Potassium, K         (Beans, kid:  2430.9)
307 NA           mg    500.00   1500.00   1500.00 Sodium, Na           (Bread, who:   737.3)
309 ZN           mg     11.00      0.00     16.32 Zinc, Zn             (Beans, kid:     6.0)
312 CU           mg      0.90      0.00      2.61 Copper, Cu           (Beans, kid:     1.3)
315 MN           mg      2.30      0.00      8.79 Manganese, Mn        (Bread, who:     3.5)
317 SE           ug     55.00      0.00    140.90 Selenium, Se         (Bread, who:    41.6)
320 VITA_RAE     ug    900.00   9000.00    900.00 Vitamin A, RAE       (Carrots, r:   607.5)
323 TOCPHA       mg     15.00      0.00     18.08 Vitamin E (alpha-toc (Nuts, almo:    10.8)
324 VITD         IU    800.00      0.00    800.00 Vitamin D            (Fish, salm:   771.1)
401 VITC         mg     90.00      0.00     90.00 Vitamin C, total asc (Broccoli, :    76.1)
404 THIA         mg      1.20      0.00      2.23 Thiamin              (Beans, kid:     1.0)
405 RIBF         mg      1.30      0.00      1.85 Riboflavin           (Beans, kid:     0.3)
406 NIA          mg     16.00      0.00     29.25 Niacin               (Fish, salm:    11.7)
410 PANTAC       mg      5.00      0.00      6.53 Pantothenic acid     (Fish, salm:     1.5)
415 VITB6A       mg      1.70      0.00      2.61 Vitamin B-6          (Fish, salm:     1.0)
417 FOL          ug    400.00      0.00   1018.39 Folate, total        (Beans, kid:   780.3)
418 VITB12       ug      2.40      0.00      8.83 Vitamin B-12         (Fish, salm:     5.1)
430 VITK1        ug    120.00      0.00    161.19 Vitamin K (phylloqui (Broccoli, :    86.7)
601 CHOLE        mg      0.00    300.00    300.00 Cholesterol          (Fish, perc:   160.0)
606 FASAT         g      0.00     20.00     18.60 Fatty acids, total s (Cheese, ch:    13.6)