最大化你的比萨口感 (Zuìdàhuà nǐ de bǐsà kǒugǎn)
打造完美的比萨口感 (Dǎzào wánměi de bǐsà kǒugǎn)
许多人都喜欢披萨,喜好范围从辣味和素食到素食者、鱼食者、食肉者、马基雅维利主义者,或者只简单地是传统的芝士爱好者。
想象一下比萨店老板面临的挑战,试图在经营业务的同时满足各种各样的顾客口味。为了解决这个困境,他们聪明地请来了一位精通SQL的数据科学家(DS)。幸运的是,根据工作描述,DS对比萨也有深深的爱。
DS的任务是设计一种解决方案,以下就是他们想出来的:下图展示了50名顾客对于20种不同比萨配料的偏好。为了保护比萨店免受潜在的与通用数据保护条例相关的法律问题的侵害,数据已被匿名处理,确保顾客对于比萨中是否放菠萝或大蒜的偏好保密。
{(0, 'L'): {2, 10, 13, 18}, (0, 'D'): {5, 8, 16}, (1, 'L'): set(), (1, 'D'): set(), (2, 'L'): set(), (2, 'D'): {0, 2, 4, 18}, (3, 'L'): {12, 13, 14}, (3, 'D'): set(), (4, 'L'): {15}, (4, 'D'): {4, 5, 6, 18}, (5, 'L'): {0, 8}, (5, 'D'): {6}, (6, 'L'): {0, 13, 14, 17}, (6, 'D'): {4, 7, 10}, (7, 'L'): {1, 6, 10, 14}, (7, 'D'): {15}, (8, 'L'): {3, 7, 18}, (8, 'D'): {4, 5, 9, 15}, (9, 'L'): {10, 15}, (9, 'D'): {8, 14, 18, 19}, (10, 'L'): set(), (10, 'D'): {7, 14, 16}, (11, 'L'): {1, 2, 12}, (11, 'D'): {3, 10}, (12, 'L'): {5, 10, 13}, (12, 'D'): {19}, (13, 'L'): {1, 8, 14, 16}, (13, 'D'): {4, 12}, (14, 'L'): {0, 10, 12}, (14, 'D'): set(), (15, 'L'): {4}, (15, 'D'): {11}, (16, 'L'): set(), (16, 'D'): {3, 8, 10, 17}, (17, 'L'): {0, 11, 17, 18}, (17, 'D'): {6, 19}, (18, 'L'): {17}, (18, 'D'): {9, 11, 19}, (19, 'L'): {4, 7, 11}, (19, 'D'): set(), (20, 'L'): {5, 8, 15, 16}, (20, 'D'): {2, 11}, (21, 'L'): set(), (21, 'D'): {0, 6, 10, 13}, (22, 'L'): {2, 5, 7, 17}, (22, 'D'): {1, 3, 18}, (23, 'L'): {3, 13}, (23, 'D'): {4, 8, 12}, (24, 'L'): {8}, (24, 'D'): {3, 5, 17, 19}, (25, 'L'): {0, 7, 9, 10}, (25, 'D'): {2, 6, 19}, (26, 'L'): {10, 18}, (26, 'D'): {3, 4, 7}, (27, 'L'): {3, 6}, (27, 'D'): {7, 9, 16}, (28, 'L'): {7, 17}, (28, 'D'): set(), (29, 'L'): set(), (29, 'D'): {4, 6}, (30, 'L'): set(), (30, 'D'): {0, 4, 5, 19}, (31, 'L'): {5, 8, 18}, (31, 'D'): {0, 12, 13}, (32, 'L'): {8}, (32, 'D'): {0, 7}, (33, 'L'): set(), (33, 'D'): {0, 2, 12}, (34, 'L'): set(), (34, 'D'): {3, 15}, (35, 'L'): set(), (35, 'D'): set(), (36, 'L'): {7}, (36, 'D'): {0, 19}, (37, 'L'): {6}, (37, 'D'): {5, 13, 15, 19}, (38, 'L'): {7, 9, 16, 18}, (38, 'D'): {3}, (39, 'L'): {10, 13, 17}, (39, 'D'): {15}, (40, 'L'): {9, 15}, (40, 'D'): {8, 10, 18, 19}, (41, 'L'): {0, 5}, (41, 'D'): {14, 16}, (42, 'L'): {4, 13}, (42, 'D'): set(), (43, 'L'): {4, 8, 16}, (43, 'D'): {6, 7, 10}, (44, 'L'): {0, 12}, (44, 'D'): {3, 5, 8, 9}, (45, 'L'): {2, 10}, (45, 'D'): set(), (46, 'L'): {2, 5, 9, 12}, (46, 'D'): set(), (47, 'L'): set(), (47, 'D'): set(), (48, 'L'): {4, 7, 13}, (48, 'D'): {1}, (49, 'L'): {0, 15}, (49, 'D'): {2, 4, 12, 13}}
Python代码
import networkx as nx
import matplotlib.pyplot as plt
pizza_ingredients = ['马苏里拉奶酪', '番茄酱', '意大利辣香肠', '蘑菇', '青椒', '洋葱', '黑橄榄', '香肠', '培根', '火腿', '菠萝', '墨西哥辣椒', '新鲜罗勒', '大蒜', '橄榄油', '帕尔香干酪', '奶酪', '菠菜', '樱桃番茄', '凤尾鱼']
plt.figure(figsize=(12,6))
for c in customers:
X= [c for e in elements]
Y= [e for e in elements]
plt.scatter(X,Y, c='grey', s=20, alpha=0.4)
x= [c for e in data[c,'L'] ]
y= [e for e in data[c,'L'] ]
plt.scatter(x,y, c='g', s=50)
x= [c for e in data[c,'D'] ]
y= [e for e in data[c,'D'] ]
plt.scatter(x,y, c='r', s=50)
plt.xticks(list(customers),rotation=90, fontweight='bold')
plt.yticks(list(elements), pizza_ingredients, fontweight='bold')
plt.ylabel('配料', fontweight='bold')
plt.xlabel('顾客', fontweight='bold')
plt.tight_layout()
fname = 'base_pizza.png'
plt.savefig(fname)
# Download the file
files.download(fname)
plt.show()
%pip install ortools
from ortools.sat.python import cp_model
def main():
model = cp_model.CpModel()
X = {e:model.NewBoolVar(f"x_{e}") for e in elements}
Sc = {c:model.NewBoolVar(f"S_{c}") for c in customers}
for c,v in Sc.items():
for e in data[c,'L']:
model.Add(v <= X[e])
for e in data[c,'D']:
model.Add(v <= 1-X[e])
expressions = [v for s,v in Sc.items()]
model.Maximize(cp_model.LinearExpr.Sum(expressions))
solver = cp_model.CpSolver()
status = solver.Solve(model)
模拟结果:
被选中的配料,包括火腿,用水平线表示,而满意的顾客用垂直金线表示。例如,顾客1是一个随和的顾客,没有特殊的偏好或厌恶,而顾客28有两个喜欢的配料(绿色)和没有讨厌的配料(红色)。
整体目标函数的总值为17。如果你对Python代码感兴趣,可以在GitHub代码仓库里找到它。请在评论部分找到它,因为LinkedIn限制带有链接的帖子。所有链接都是平等的,但有些链接更平等。
完全忽略讨厌的配料:
如果忽略配料的厌恶,并限制允许的配料数量为10,则结果如下:
28个满意的顾客。
容忍最多一个讨厌的配料:
如果限制允许的配料数量为10,则结果如下:
21个满意的顾客。
容忍如果喜欢的配料多于讨厌的配料:
如果限制允许的配料数量为10,则结果如下:
27位满意的客户。
我明白这只是一个简化的情景,在现实世界的比萨店中,还有许多其他考虑因素和限制因素,所以请放松心情,享受你的比萨。
这个问题的灵感来自于谷歌-hash-code-2022-practice-problem。
Github: https://github.com/OptimizationExpert/Pyomo
尽情享受吧!




