[PYTHON] Think about menus by combinatorial optimization

Problem

My doctor told me to limit the calories in my weekly diet. In addition, the minimum required amount of nutrient A and nutrient B was also instructed. How can I eat what I like as much as possible?

Formulation

It is an allocation problem in Combinatorial optimization problem. Let's assume that cooking candidates are given, and let's express which one to choose with the 0-1 variable $ x $.

Variables $ x_i \ in \ {0, 1 \} $ $ i $ Whether to choose the second dish >
Objective Function $ \ sum_i {Preference_i x_i} $ $ \ rightarrow $ Maximum
Constraints $ \ sum_i {x_i} = 7 $ Choose 7 days
$ \ sum_i {calorie_i x_i} \ le 90 $ calorie restriction
$ \ sum_i {Nutrients A_i x_i} \ ge 95 $ Minimum acquisition amount
$ \ sum_i {Nutrients B_i x_i} \ ge 95 $ Minimum acquisition amount

Try to solve with python

The optimization library is [pulp](http://qiita.com/Tsutomu-KKE@github/items/bfbf4c185ed7004b5721#%E3%82%BD%E3%83%95%E3%83%88%E3%81% Use AE% E3% 82% A4% E3% 83% B3% E3% 82% B9% E3% 83% 88% E3% 83% BC% E3% 83% AB). First, let's create dummy data.

python


import numpy as np, pandas as pd
from pulp import *
menu = ['beef bowl', 'Oyakodon', 'Pork cutlet on rice', 'Tuna bowl', 'Negitoro bowl', 'chirashi sushi',
        'Eggplant with Mao', 'Doria', 'Omelette rice', 'Fried rice', 'Curry and rice']
n = len(menu)
np.random.seed(1)
a = pd.DataFrame({
        'Cooking name': menu,
        'calorie': np.random.randint(10,20,n),
        'Nutrient A': np.random.randint(10,20,n),
        'Nutrient B': np.random.randint(10,20,n),
        'Preference': np.random.randint(10,20,n),
    })
print(a)
Cooking name Preference calorie Nutrient A Nutrient B
0 beef bowl 18 15 14
1 Oyakodon 13 18 15
2 Pork cutlet on rice 19 19 12
3 Tuna bowl 18 15 14
4 Negitoro bowl 17 10 12
5 chirashi sushi 13 10 14
6 Eggplant with Mao 16 11 17
7 Doria 15 17 17
8 Omelette rice 11 16 19
9 Fried rice 19 19 11
10 Curry and rice 13 12 17

Let's solve it.

python


m = LpProblem(sense=LpMaximize) #Maximization problem
a['x'] = [LpVariable('x%d'%i, cat=LpBinary) for i in range(n)] #select/do not do
m += lpDot(a.Preference, a.x) # Preferenceを最大化
m += lpSum(a.x) == 7 #Menu for one week
m += lpDot(a.calorie, a.x) <= 90
m += lpDot(a.Nutrient A, a.x) >= 95
m += lpDot(a.Nutrient B, a.x) >= 95
m.solve()
if m.status == 1: # Optimal
    a['val'] = a.x.apply(lambda v: value(v)) #result
    print(a[a.val == 1].Cooking name)
>>>
0 beef bowl
3 Tekkadon
4 Negitoro bowl
5 Chirashizushi
6 Eggplant with Mao
7 Doria
10 curry rice

Docker If you want to give it a try with Docker, run the following to open the host in your browser and Jupyter will start. The library is also installed variously.

docker run -d -p 80:8888 tsutomu7/jupyter

that's all

Recommended Posts