提问人:superepp 提问时间:6/27/2023 更新时间:6/27/2023 访问量:44
KeyError:0 尝试运行 LPP 时
KeyError: 0 When attempting to run my LPP
问:
我尝试使用 python 构建和解决线性规划问题,但是在运行时收到以下错误:
KeyError: 0
以下是我正在使用的代码:
bfast = 1
lunchanddinner = 2
mealstypes = list(set(meals_dataset.Type))
constraints = {'breakfast':bfast,'lunch_dinner':lunchanddinner}
meals = meals_dataset.Meal.tolist()
calories = dict( zip( meals, np.array(meals_dataset.Calories.tolist())))
x = pulp.LpVariable.dicts( "x", indexs = meals, lowBound=0, upBound=1, cat='Integer', indexStart=[])
proteins = meals_dataset.Protein.tolist()
def model(minprotein):
prob = pulp.LpProblem("Meal Plan", LpMinimize)
prob += pulp.lpSum( [ x[i]*calories[i] for i in meals])
for i in range(len(mealstypes)):
type_data = meals_dataset[meals_dataset.Type==mealstypes[i]]
boundary_condition = np.arange(type_data.index.min(),type_data.index.max())
const = constraints[mealstypes[i]]
prob += pulp.lpSum( [ x[j] for j in boundary_condition ] )==const
prob += pulp.lpSum( [ x[i]*proteins[i] for i in range(len(x))])<= minprotein
return prob
def find_best_plan(minprotein):
prob = model(minprotein)
prob.solve()
variables = []
values = []
for v in prob.variables():
variable = v.name
value = v.varValue
variables.append(variable)
values.append(value)
values = np.array(values).astype(int)
meal_list = pd.DataFrame(np.array([variables,values]).T,columns = ['Variable','Optimal Value'])
meal_list['Optimal Value'] = meal_list['Optimal Value'].astype(int)
squad = meal_list[meal_list['Optimal Value']!=0]
squad_meals = meals_dataset.Meal.loc[np.array(squad.Variable.str.split('_').tolist())[:,1].astype(int)]
squad_type = meals_dataset.Type.loc[np.array(squad.Variable.str.split('_').tolist())[:,1].astype(int)]
return pd.DataFrame([squad_meals,squad_type]).T
然后,我运行以下命令
find_best_plan_80 = find_best_plan(80)
这会导致错误
KeyError Traceback (most recent call last)
<ipython-input-38-43f957c4ddba> in <cell line: 1>()
----> 1 find_best_plan_80 = find_best_plan(80)
2 frames
<ipython-input-36-07827a9fc028> in <listcomp>(.0)
10 boundary_condition = np.arange(type_data.index.min(),type_data.index.max())
11 const = constraints[mealstypes[i]]
---> 12 prob += pulp.lpSum( [ x[j] for j in boundary_condition ] )==const
13 prob += pulp.lpSum( [ x[i]*proteins[i] for i in range(len(x))])<= minprotein
14 return prob
KeyError: 0
我被困在这里,无法弄清楚我的问题是什么。作为参考,这是我使用的数据库:
Meal Calories Protein Type
0 weetabix_milk_applejuice 298.125 6.47025 breakfast
1 eggs_bacon_toast 635.500 32.41750 breakfast
2 proteinyog_raspberries 238.600 43.71750 breakfast
3 pancakes_syrup 418.500 9.61200 breakfast
4 turkeybacon_omelette 374.000 26.75750 breakfast
5 chicken_rice_broccoli 519.200 51.88300 lunch or dinner
6 prawn_stir_fry 559.200 37.99650 lunch or dinner
7 steak_fries_asparagus 867.100 67.16000 lunch or dinner
8 chicken_caesar_salad 242.900 35.78700 lunch or dinner
9 chicken_fajitas 804.560 58.12480 lunch or dinner
10 beefpie_mash_broccoli 736.200 23.33600 lunch or dinner
11 tuna_jp 425.600 32.28300 lunch or dinner
12 beef_pasta 652.250 55.38000 lunch or dinner
13 blt 513.000 15.46350 lunch or dinner
14 chicken_sandwich 397.200 29.76750 lunch or dinner
任何帮助将不胜感激。
答:
1赞
AirSquid
6/27/2023
#1
您在索引变量时犯了一些基本错误。如果你看一下这个错误,它告诉你它不存在(关键错误)......x[0]
您正在定义 x 以 {tuna_jp, blt, ...} 等 Meals 集进行索引,但随后您开始使用 from 和 的整数进行索引。这些都行不通。选择名称或整数。boundary_condition
range(len(x))
我强烈建议在开始时减轻大量混乱,即放弃并只使用基本的 python 字典。它更干净,您将能够专注于建模。然后,如果问题变得更大,或者您有一个大型数据文件,那么也许.pandas
numpy
pandas
1赞
Reinderien
6/27/2023
#2
Pandas 实际上是一种非常合理的 Pulp 做事方式——恕我直言,它比裸露的 Pulp 更好——但它需要正确完成,而且它没有出现在原始代码中。
from io import StringIO
import pandas as pd
import pulp
dstr = ''' Meal,Calories, Protein, Type
weetabix_milk_applejuice, 298.125, 6.47025, breakfast
eggs_bacon_toast, 635.500,32.41750, breakfast
proteinyog_raspberries, 238.600,43.71750, breakfast
pancakes_syrup, 418.500, 9.61200, breakfast
turkeybacon_omelette, 374.000,26.75750, breakfast
chicken_rice_broccoli, 519.200,51.88300,lunch or dinner
prawn_stir_fry, 559.200,37.99650,lunch or dinner
steak_fries_asparagus, 867.100,67.16000,lunch or dinner
chicken_caesar_salad, 242.900,35.78700,lunch or dinner
chicken_fajitas, 804.560,58.12480,lunch or dinner
beefpie_mash_broccoli, 736.200,23.33600,lunch or dinner
tuna_jp, 425.600,32.28300,lunch or dinner
beef_pasta, 652.250,55.38000,lunch or dinner
blt, 513.000,15.46350,lunch or dinner
chicken_sandwich, 397.200,29.76750,lunch or dinner
'''
with StringIO(dstr) as f:
df = pd.read_csv(f, skipinitialspace=True, index_col='Meal')
def make_select(row: pd.Series) -> pulp.LpVariable:
return pulp.LpVariable(name='assign_' + row.name, cat=pulp.LpBinary)
df['Select'] = df.apply(make_select, axis=1)
prob = pulp.LpProblem(name='meal_plan', sense=pulp.LpMinimize)
prob.objective = df.Calories.dot(df.Select)
prob.addConstraint(
name='min_protein',
constraint=df.Protein.dot(df.Select) >= 80,
)
prob.addConstraint(
name='breakfasts',
constraint=df[df.Type == 'breakfast'].Select.sum() == 1,
)
prob.addConstraint(
name='dinners',
constraint=df[df.Type == 'lunch or dinner'].Select.sum() == 2,
)
print(prob)
prob.solve()
assert prob.status == pulp.LpStatusOptimal
df['Select'] = df.Select.apply(pulp.LpVariable.value)
print(df)
meal_plan:
MINIMIZE
652.25*assign_beef_pasta + 736.2*assign_beefpie_mash_broccoli + 513.0*assign_blt + 242.9*assign_chicken_caesar_salad + 804.56*assign_chicken_fajitas + 519.2*assign_chicken_rice_broccoli + 397.2*assign_chicken_sandwich + 635.5*assign_eggs_bacon_toast + 418.5*assign_pancakes_syrup + 559.2*assign_prawn_stir_fry + 238.6*assign_proteinyog_raspberries + 867.1*assign_steak_fries_asparagus + 425.6*assign_tuna_jp + 374.0*assign_turkeybacon_omelette + 298.125*assign_weetabix_milk_applejuice + 0.0
SUBJECT TO
min_protein: 55.38 assign_beef_pasta + 23.336 assign_beefpie_mash_broccoli
+ 15.4635 assign_blt + 35.787 assign_chicken_caesar_salad
+ 58.1248 assign_chicken_fajitas + 51.883 assign_chicken_rice_broccoli
+ 29.7675 assign_chicken_sandwich + 32.4175 assign_eggs_bacon_toast
+ 9.612 assign_pancakes_syrup + 37.9965 assign_prawn_stir_fry
+ 43.7175 assign_proteinyog_raspberries + 67.16 assign_steak_fries_asparagus
+ 32.283 assign_tuna_jp + 26.7575 assign_turkeybacon_omelette
+ 6.47025 assign_weetabix_milk_applejuice >= 80
breakfasts: assign_eggs_bacon_toast + assign_pancakes_syrup
+ assign_proteinyog_raspberries + assign_turkeybacon_omelette
+ assign_weetabix_milk_applejuice = 1
dinners: assign_beef_pasta + assign_beefpie_mash_broccoli + assign_blt
+ assign_chicken_caesar_salad + assign_chicken_fajitas
+ assign_chicken_rice_broccoli + assign_chicken_sandwich
+ assign_prawn_stir_fry + assign_steak_fries_asparagus + assign_tuna_jp = 2
VARIABLES
0 <= assign_beef_pasta <= 1 Integer
0 <= assign_beefpie_mash_broccoli <= 1 Integer
0 <= assign_blt <= 1 Integer
0 <= assign_chicken_caesar_salad <= 1 Integer
0 <= assign_chicken_fajitas <= 1 Integer
0 <= assign_chicken_rice_broccoli <= 1 Integer
0 <= assign_chicken_sandwich <= 1 Integer
0 <= assign_eggs_bacon_toast <= 1 Integer
0 <= assign_pancakes_syrup <= 1 Integer
0 <= assign_prawn_stir_fry <= 1 Integer
0 <= assign_proteinyog_raspberries <= 1 Integer
0 <= assign_steak_fries_asparagus <= 1 Integer
0 <= assign_tuna_jp <= 1 Integer
0 <= assign_turkeybacon_omelette <= 1 Integer
0 <= assign_weetabix_milk_applejuice <= 1 Integer
Welcome to the CBC MILP Solver
Version: 2.10.3
Build Date: Dec 15 2019
Result - Optimal solution found
Objective value: 878.70000000
Enumerated nodes: 0
Total iterations: 0
Time (CPU seconds): 0.01
Time (Wallclock seconds): 0.01
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.01 (Wallclock seconds): 0.01
Calories Protein Type Select
Meal
weetabix_milk_applejuice 298.125 6.47025 breakfast 0.0
eggs_bacon_toast 635.500 32.41750 breakfast 0.0
proteinyog_raspberries 238.600 43.71750 breakfast 1.0
pancakes_syrup 418.500 9.61200 breakfast 0.0
turkeybacon_omelette 374.000 26.75750 breakfast 0.0
chicken_rice_broccoli 519.200 51.88300 lunch or dinner 0.0
prawn_stir_fry 559.200 37.99650 lunch or dinner 0.0
steak_fries_asparagus 867.100 67.16000 lunch or dinner 0.0
chicken_caesar_salad 242.900 35.78700 lunch or dinner 1.0
chicken_fajitas 804.560 58.12480 lunch or dinner 0.0
beefpie_mash_broccoli 736.200 23.33600 lunch or dinner 0.0
tuna_jp 425.600 32.28300 lunch or dinner 0.0
beef_pasta 652.250 55.38000 lunch or dinner 0.0
blt 513.000 15.46350 lunch or dinner 0.0
chicken_sandwich 397.200 29.76750 lunch or dinner 1.0
评论
1赞
AirSquid
6/27/2023
我喜欢反驳意见,尤其是当有漂亮的代码备份时。我只为光滑的 StringIO => 数据帧实现投了赞成票。在那里学到了一些东西!;)
评论