我想创建库存履行优化计划。
每个 Item 有 4 个数据框。我想建议每件商品的履行数量。
目标:
任何物品的现有数量(df2)小于安全库存数量(df3),我们希望满足批次数量(df4)的乘数
限制:
总履行重量应小于1000KG(最大容量小于一辆卡车)
df1
商品# | 重量KG |
---|---|
细胞1 | 细胞2 |
细胞3 | 4 号电池 |
df2
商品# | 现有数量 |
---|---|
细胞1 | 细胞2 |
细胞3 | 4 号电池 |
df3
商品# | 安全库存数量 |
---|---|
细胞1 | 细胞2 |
细胞3 | 4 号电池 |
df4
商品# | 批量 |
---|---|
细胞1 | 细胞2 |
细胞3 | 4 号电池 |
我尝试了如下代码,但认为它是不正确的。
请建议正确的代码或方法来实现目标
m=model_max()
v1={(i):LpVariable('v%d'%(i),lowBound=0) for i in range(len(df4))}
m+=lpSum(df4.iloc[i]*v1[i] for i in range (len(df4)))
for i in range(len(df_lt)):
m+= lpSum(df_lt.iloc[i]*v1[i])>=df_ss.iloc[i]
如果我正确理解你的问题,你可以使用类似的东西:
# == Necessary Imports ============================================================
import pulp
import pandas as pd
# == Input Data ===================================================================
MAX_WEIGHT = 1_000
df1 = pd.DataFrame([["SKU1", 13], ["SKU2", 22]], columns=["Item #", "Weight KG"])
df2 = pd.DataFrame([["SKU1", 150], ["SKU2", 80]], columns=["Item #", "On Hand QTY"])
df3 = pd.DataFrame([["SKU1", 100], ["SKU2", 120]], columns=["Item #", "Safety Stock QTY"])
df4 = pd.DataFrame([["SKU1", 10], ["SKU2", 5]], columns=["Item #", "Lot QTY"])
# == Optimization =================================================================
# -- Create optimization problem instance -----------------------------------------
prob = pulp.LpProblem("Inventory_Optimization", sense=pulp.LpMinimize)
# NOTE: The parameter `sense` determines whether we want to maximize of minimize
# our objective function
# -- Create problem variables -----------------------------------------------------
items = df1["Item #"].unique() # List of unique "Item #" values
# For each "Item #" we have, we'll create two variables:
# - Allocated (integer): quantity of items to allocate.
# - Lot_Allocated (integer): quantity of item lots to allocate.
allocations = pd.DataFrame(
[
[
item,
pulp.LpVariable(name=item, lowBound=0, cat=pulp.LpInteger),
pulp.LpVariable(name=f"LOT_{item}", lowBound=0, cat=pulp.LpInteger),
] for item in items
], columns=["Item #", "Allocated", "Lot_Allocated"]
)
# Merge our input and variables dataframes, to create a table with all the information we need.
allocations = (
allocations.merge(df1, on="Item #", how="inner")
.merge(df2, on="Item #", how="inner")
.merge(df3, on="Item #", how="inner")
.merge(df4, on="Item #", how="inner")
)
# -- Create problem constraints ------------------------------------------------------
# Now we'll define our problem constraints.
# Constraint 1: Total Weight of Items allocated <= 1,000Kg
# Where:
# - Total Weight of Items allocated = Σ(Allocated(i) * Weight KG(i)); for i in range Items
prob += pulp.lpSum(allocations["Allocated"] * allocations["Weight KG"]) <= MAX_WEIGHT, "TOTAL_ALLOCATIONS_LEQ_MAX_WEIGHT"
# Constraint 2: For each "Item #", if "On Hand QTY" >= "Safety Stock QTY" --> Then Allocated == 0
prob += pulp.lpSum(allocations[allocations["On Hand QTY"] >= allocations["Safety Stock QTY"]]["Allocated"]) == 0, "ON_HAND_LESS_SAFETY"
# Constraint 3: Allocated(i)/Lot QTY(i) == LOT_CONSTRAINT(i)
for index, row in allocations.iterrows():
prob += row["Allocated"] * row["Lot QTY"]**-1 == row["Lot_Allocated"], f"LOT_CONSTRAINT_{index}"
# -- Set Objective Function ------------------------------------------------------------
# We'll define that our objective function will be to reach the
# Total Weight of Items allocated as close to 1,000Kg as possible.
obj = MAX_WEIGHT - pulp.lpSum(allocations["Allocated"] * allocations["Weight KG"])
prob.setObjective(obj)
# -- Solve the Optimization Problem ----------------------------------------------------
print(pulp.LpStatus[prob.solve(pulp.PULP_CBC_CMD(msg=False))])
if prob.status != 1:
raise ValueError(f"Failed to solve optimization problem. Status: {pulp.LpStatus[prob.status]}")
allocations[["Allocated", "Lot_Allocated"]] = allocations[["Allocated", "Lot_Allocated"]].applymap(lambda value: value.value()).astype(int)
allocations
# Returns:
#
# Item # Allocated Lot_Allocated Weight KG On Hand QTY Safety Stock QTY Lot QTY
# 0 SKU1 0 0 13 150 100 10
# 1 SKU2 45 9 22 80 120 5
输出:
商品# | 已分配 | 已分配批次 | 重量KG | 现有数量 | 安全库存数量 | 批量 |
---|---|---|---|---|---|---|
SKU1 | 0 | 0 | 13 | 150 | 100 | 10 |
SKU2 | 45 | 9 | 22 | 80 | 120 | 5 |