Pulp优化工具中实现选中SKU品类数不超过指定值的约束设置问题
解决方案
你之前写的约束无法生效的原因是:df['SKU'].count(distinct)是统计数据集固定的SKU总数,和优化变量的取值没有关联,自然不会对求解结果产生限制。
要实现「选中的SKU品类总数不超过500」的约束,需要引入二进制辅助变量标记SKU是否被选中,具体实现步骤如下:
- 定义二进制辅助变量:为每行对应的SKU定义一个0-1变量
y[idx],取值为1时代表该SKU被选中,取值为0时代表未被选中。 - 绑定原变量和辅助变量的关联:加约束规则,如果某SKU的分配量
x[idx]>0,则对应的y[idx]必须为1;如果y[idx]=0,则该SKU的分配量必须为0。 - 新增SKU总数约束:所有二进制变量的总和≤500,即为你需要的品类数限制。
完整修改后的代码示例
import pandas as pd import pulp # 你原有的读取数据代码 df=pd.read_excel(ruta+"actual/202109.xlsx", nrows=20) max_uni = 你原有定义的最大单位数 # 请补充你自己定义的max_uni赋值 # 创建变量和模型 x = pulp.LpVariable.dicts("x", df.index, lowBound=0) # 新增:二进制辅助变量,标记SKU是否被选中 y = pulp.LpVariable.dicts("y", df.index, cat='Binary') mod = pulp.LpProblem("Budget", pulp.LpMaximize) # 目标函数(和你原来的逻辑一致) objvals = {idx: (1.0)*(df['costo_unitario'][idx]) for idx in df.index} mod += sum([x[idx]*objvals[idx] for idx in df.index]) # 原有上下界约束修改:绑定x和y的关系 for idx in df.index: # 当y[idx]为0时,x[idx]只能取0;y[idx]为1时,x[idx]上限为最大库存 mod += x[idx] <= df['unidades_sobrestock'][idx] * y[idx] # 原有总库存预算约束(保持不变) mod += sum([x[idx] for idx in df.index]) <= max_uni # 新增:选中SKU总数不超过500的约束 mod += sum([y[idx] for idx in df.index]) <= 500 # 求解模型 mod.solve() # 输出结果 for idx in df.index: print(f"{idx} 分配量:{x[idx].value()},是否选中SKU:{y[idx].value()}") print(f"目标值:{pulp.value(mod.objective)}")
特殊情况说明
如果你的数据框中存在同一个SKU对应多行记录的情况,需要先按SKU编号分组,为每个唯一SKU定义一个二进制变量,再把该SKU下所有行的x变量和同一个y变量绑定即可。
内容的提问来源于stack exchange,提问作者Gustavo Moreno
相关产品推荐
相关产品推荐

