Python 背包问题——使用所选物品的平均值作为约束条件?
Python Knapsack problem - using the average value of the selected items as a constraint?
我对 python 还是比较陌生,所以我不知道如何完成某项壮举。
我想做什么:我有一个包含两列的 Excel 文件 - 卖出和保证金。可能有可变数量的行。我需要找到一个“最适合”,其中 n# 的销售行的总和在目标销售量的 5% 以内并且平均保证金也在目标保证金 % 的 5% 以内(如果有解决方案,如果不再增加 % 公差和 运行。但我可以稍后解决)。
通过谷歌搜索,我了解到这是一个多约束背包问题,并且能够找到一些示例来解决。
我借用的代码来自这里:https://towardsdatascience.com/solving-the-multiple-knapsack-problem-with-google-or-tools-e961dfc8288e
我的问题:我不知道如何设置一个约束条件,使放入包中的物品的平均边距接近目标平均边距。
这是我在上面的网站上修改后的代码,我在其中使用随机数据进行销售和保证金:
from ortools.linear_solver import pywraplp
solver = solver = pywraplp.Solver.CreateSolver('SCIP')
data = {}
sell = [8520,9600,5340,8379,846,1098,1510,4954,1039,620,795,3260,75,200,75]
margin = [25, 25, 25, 34, 25, 25, 25, 25, 25, 25, 27, 20, 100, 27, 100]
assert len(sell) == len(margin)
data['values'] = values
data['sell'] = sell
data['margin'] = margin
data['items'] = list(range(len(sell)))
data['num_items'] = len(sell)
number_bags = 1 #All have the same capacity of 50 pounds
data['target_amount'] = [9262]
data['avg_margin'] = [27]
data['bags'] = list(range(number_bags))
assert len(data['target_amount']) == number_bags
assert len(data['target_amount']) == len(data['avg_margin'])
print('sell:',*data['sell'])
print('margin:',*data['margin'])
print("Number of Items:", data['num_items'])
print("Number of Knapsacks:" , number_bags)
x = {}
for i in data['items']:
for j in data['bags']:
x[(i,j)] = solver.IntVar(0,1,'x_%i_%i' % (i, j))
#Constraint for an item being placed in 1 knapsack
for i in data['items']:
solver.Add(sum(x[i,j] for j in data['bags'])<=1)
#Knapsack Capacity Constraint
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['sell'][i]
for i in data['items']) <= data['target_amount'][j])
#margin Constraint
#for j in data['bags']:
# solver.Add(sum(x[(i,j)]*data['margin'][i]
# for i in data['items']) <= data['target_amount'][j])
#objective function
objective = solver.Objective()
for i in data['items']:
for j in data['bags']:
objective.SetCoefficient(x[(i,j)], data['sell'][i])
objective.SetMaximization()
solv = solver.Solve()
if solv == pywraplp.Solver.OPTIMAL:
print('Total Packed Value:', objective.Value())
total_Sell = 0
for j in data['bags']:
bag_Sell = 0
avg_margin= 0
count = 0
print('\n','Bag', j+1 , '\n')
for i in data['items']:
if x[i,j].solution_value()>0:
print('Line:', i ,
'Sell', data['sell'][i],
'margin',data['margin'][i],
)
bag_Sell += data['sell'][i]
avg_margin += data['margin'][i]
count += 1
print('Packed Knapsack Sell: ', bag_Sell)
print('Packed Knapsack margin: ', round(avg_margin / count, 2))
else:
print("There is no optimal solution")
Is this even possible? Am I just way out of my league?
Thanks
使用数学(和一张纸)通常比使用代码更好。所以我们有:
sum(i,x[i]*m[i])
---------------- ≈ Target
sum(i,x[i])
第一步是去掉除法:
sum(i,x[i]*m[i]) ≈ Target * sum(i,x[i])
或者
|sum(i,x[i]*m[i]) - Target * sum(i,x[i])| <= MaxDeviation
这可以线性化为:
-MaxDeviation <= sum(i,x[i]*m[i]) - Target * sum(i,x[i]) <= MaxDeviation
添加平均边距约束不是很困难,一旦你写下来。
将平均边距保持在两个范围内的约束
您可以在模型中添加以下内容:
min_acceptable_margin = data['target_margin'][0] * 0.95
max_acceptable_margin = data['target_margin'][0] * 1.05
#Average Margin Constraints
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * min_acceptable_margin
for i in data['items']) >= 0 , name=f"GT_Target_Avg")
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * max_acceptable_margin
for i in data['items']) <= 0 , name=f"LT_Target_Avg")
如您所见,我们在 LP 中写出了保持约束线性的条款。
既然你说你是Python的新手,我提供完整的代码:
完整工作代码(OR-Tools LP)
from ortools.linear_solver import pywraplp
solver = solver = pywraplp.Solver.CreateSolver('SCIP')
sell = [8520,9600,5340,8379,846,1098,1510,4954,1039,620,795,3260,75,200,75]
margin = [25, 25, 25, 34, 25, 25, 25, 25, 25, 25, 27, 20, 100, 27, 100]
target_margin = [40]
bag_capacities = [9262]
def prepare_data():
data = {}
assert len(sell) == len(margin)
data['sell'] = sell
data['margin'] = margin
data['items'] = list(range(len(sell)))
data['num_items'] = len(sell)
number_bags = 1
data['target_amount'] = bag_capacities
data['target_margin'] = target_margin
data['bags'] = list(range(number_bags))
assert len(data['target_amount']) == number_bags
assert len(data['target_amount']) == len(data['target_margin'])
print('sell:',*data['sell'])
print('margin:',*data['margin'])
print("Number of Items:", data['num_items'])
print("Number of Knapsacks:" , number_bags)
return data
data = prepare_data()
print(data)
#Start Formulating the problem
x = {}
for i in data['items']:
for j in data['bags']:
x[(i,j)] = solver.IntVar(0,1,'x_%i_%i' % (i, j))
#Constraint for an item being placed in 1 knapsack
for i in data['items']:
solver.Add(sum(x[i,j] for j in data['bags'])<=1, name="Max_One_Item"+str(i))
#Knapsack Capacity Constraint
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['sell'][i]
for i in data['items']) <= data['target_amount'][j], name=f"BagCapacity_{i}")
#Average Margin Constraints
min_acceptable_margin = data['target_margin'][0] * 0.95
max_acceptable_margin = data['target_margin'][0] * 1.05
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * min_acceptable_margin
for i in data['items']) >= 0 , name=f"GT_Target_Avg")
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * max_acceptable_margin
for i in data['items']) <= 0 , name=f"LT_Target_Avg")
#objective function
objective = solver.Objective()
for i in data['items']:
for j in data['bags']:
objective.SetCoefficient(x[(i,j)], data['sell'][i])
objective.SetMaximization()
#Call the solver
solv = solver.Solve()
#Print the results
if solv == pywraplp.Solver.OPTIMAL:
print('Total Packed Value:', objective.Value())
total_Sell = 0
for j in data['bags']:
bag_Sell = 0
avg_margin= 0
count = 0
print('\n','Bag', j+1 , '\n')
for i in data['items']:
if x[i,j].solution_value()>0:
print('Selected:', i ,
'Sell', data['sell'][i],
'margin',data['margin'][i],
)
bag_Sell += data['sell'][i]
avg_margin += data['margin'][i]
count += 1
print('Packed Knapsack Sell: ', bag_Sell)
print('Avg Packed Knapsack margin: ', round(avg_margin / count, 2))
print(f'Target Margin {data["target_margin"][0]} (Min {min_acceptable_margin} Max {max_acceptable_margin})')
else:
print("There is no optimal solution")
当我用上面的数字运行时,我得到了以下结果:
Total Packed Value: 9109.0
Bag 1
Selected: 7 Sell 4954 margin 25
Selected: 9 Sell 620 margin 25
Selected: 11 Sell 3260 margin 20
Selected: 12 Sell 75 margin 100
Selected: 13 Sell 200 margin 27
Packed Knapsack Sell: 9109
Avg Packed Knapsack margin: 39.4
Target Margin 40 (Min 38.0 Max 42.0)
调试时的有用命令
一些方便的命令可以帮助您调试 LP:
print('Number of variables =', solver.NumVariables())
print('Number of constraints =', solver.NumConstraints())
最后,最后一个非常有用的技巧。把求解器看到的公式写出来就好了。
#Use this to print out the ORTOOLS Formulation
print(solver.ExportModelAsLpFormat(False).replace('\', '').replace(',_', ','), sep='\n')
希望能帮助您前进。
我对 python 还是比较陌生,所以我不知道如何完成某项壮举。
我想做什么:我有一个包含两列的 Excel 文件 - 卖出和保证金。可能有可变数量的行。我需要找到一个“最适合”,其中 n# 的销售行的总和在目标销售量的 5% 以内并且平均保证金也在目标保证金 % 的 5% 以内(如果有解决方案,如果不再增加 % 公差和 运行。但我可以稍后解决)。
通过谷歌搜索,我了解到这是一个多约束背包问题,并且能够找到一些示例来解决。 我借用的代码来自这里:https://towardsdatascience.com/solving-the-multiple-knapsack-problem-with-google-or-tools-e961dfc8288e
我的问题:我不知道如何设置一个约束条件,使放入包中的物品的平均边距接近目标平均边距。
这是我在上面的网站上修改后的代码,我在其中使用随机数据进行销售和保证金:
from ortools.linear_solver import pywraplp
solver = solver = pywraplp.Solver.CreateSolver('SCIP')
data = {}
sell = [8520,9600,5340,8379,846,1098,1510,4954,1039,620,795,3260,75,200,75]
margin = [25, 25, 25, 34, 25, 25, 25, 25, 25, 25, 27, 20, 100, 27, 100]
assert len(sell) == len(margin)
data['values'] = values
data['sell'] = sell
data['margin'] = margin
data['items'] = list(range(len(sell)))
data['num_items'] = len(sell)
number_bags = 1 #All have the same capacity of 50 pounds
data['target_amount'] = [9262]
data['avg_margin'] = [27]
data['bags'] = list(range(number_bags))
assert len(data['target_amount']) == number_bags
assert len(data['target_amount']) == len(data['avg_margin'])
print('sell:',*data['sell'])
print('margin:',*data['margin'])
print("Number of Items:", data['num_items'])
print("Number of Knapsacks:" , number_bags)
x = {}
for i in data['items']:
for j in data['bags']:
x[(i,j)] = solver.IntVar(0,1,'x_%i_%i' % (i, j))
#Constraint for an item being placed in 1 knapsack
for i in data['items']:
solver.Add(sum(x[i,j] for j in data['bags'])<=1)
#Knapsack Capacity Constraint
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['sell'][i]
for i in data['items']) <= data['target_amount'][j])
#margin Constraint
#for j in data['bags']:
# solver.Add(sum(x[(i,j)]*data['margin'][i]
# for i in data['items']) <= data['target_amount'][j])
#objective function
objective = solver.Objective()
for i in data['items']:
for j in data['bags']:
objective.SetCoefficient(x[(i,j)], data['sell'][i])
objective.SetMaximization()
solv = solver.Solve()
if solv == pywraplp.Solver.OPTIMAL:
print('Total Packed Value:', objective.Value())
total_Sell = 0
for j in data['bags']:
bag_Sell = 0
avg_margin= 0
count = 0
print('\n','Bag', j+1 , '\n')
for i in data['items']:
if x[i,j].solution_value()>0:
print('Line:', i ,
'Sell', data['sell'][i],
'margin',data['margin'][i],
)
bag_Sell += data['sell'][i]
avg_margin += data['margin'][i]
count += 1
print('Packed Knapsack Sell: ', bag_Sell)
print('Packed Knapsack margin: ', round(avg_margin / count, 2))
else:
print("There is no optimal solution")
Is this even possible? Am I just way out of my league?
Thanks
使用数学(和一张纸)通常比使用代码更好。所以我们有:
sum(i,x[i]*m[i])
---------------- ≈ Target
sum(i,x[i])
第一步是去掉除法:
sum(i,x[i]*m[i]) ≈ Target * sum(i,x[i])
或者
|sum(i,x[i]*m[i]) - Target * sum(i,x[i])| <= MaxDeviation
这可以线性化为:
-MaxDeviation <= sum(i,x[i]*m[i]) - Target * sum(i,x[i]) <= MaxDeviation
添加平均边距约束不是很困难,一旦你写下来。
将平均边距保持在两个范围内的约束
您可以在模型中添加以下内容:
min_acceptable_margin = data['target_margin'][0] * 0.95
max_acceptable_margin = data['target_margin'][0] * 1.05
#Average Margin Constraints
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * min_acceptable_margin
for i in data['items']) >= 0 , name=f"GT_Target_Avg")
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * max_acceptable_margin
for i in data['items']) <= 0 , name=f"LT_Target_Avg")
如您所见,我们在 LP 中写出了保持约束线性的条款。
既然你说你是Python的新手,我提供完整的代码:
完整工作代码(OR-Tools LP)
from ortools.linear_solver import pywraplp
solver = solver = pywraplp.Solver.CreateSolver('SCIP')
sell = [8520,9600,5340,8379,846,1098,1510,4954,1039,620,795,3260,75,200,75]
margin = [25, 25, 25, 34, 25, 25, 25, 25, 25, 25, 27, 20, 100, 27, 100]
target_margin = [40]
bag_capacities = [9262]
def prepare_data():
data = {}
assert len(sell) == len(margin)
data['sell'] = sell
data['margin'] = margin
data['items'] = list(range(len(sell)))
data['num_items'] = len(sell)
number_bags = 1
data['target_amount'] = bag_capacities
data['target_margin'] = target_margin
data['bags'] = list(range(number_bags))
assert len(data['target_amount']) == number_bags
assert len(data['target_amount']) == len(data['target_margin'])
print('sell:',*data['sell'])
print('margin:',*data['margin'])
print("Number of Items:", data['num_items'])
print("Number of Knapsacks:" , number_bags)
return data
data = prepare_data()
print(data)
#Start Formulating the problem
x = {}
for i in data['items']:
for j in data['bags']:
x[(i,j)] = solver.IntVar(0,1,'x_%i_%i' % (i, j))
#Constraint for an item being placed in 1 knapsack
for i in data['items']:
solver.Add(sum(x[i,j] for j in data['bags'])<=1, name="Max_One_Item"+str(i))
#Knapsack Capacity Constraint
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['sell'][i]
for i in data['items']) <= data['target_amount'][j], name=f"BagCapacity_{i}")
#Average Margin Constraints
min_acceptable_margin = data['target_margin'][0] * 0.95
max_acceptable_margin = data['target_margin'][0] * 1.05
for j in data['bags']:
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * min_acceptable_margin
for i in data['items']) >= 0 , name=f"GT_Target_Avg")
solver.Add(sum(x[(i,j)]*data['margin'][i] - x[(i,j)] * max_acceptable_margin
for i in data['items']) <= 0 , name=f"LT_Target_Avg")
#objective function
objective = solver.Objective()
for i in data['items']:
for j in data['bags']:
objective.SetCoefficient(x[(i,j)], data['sell'][i])
objective.SetMaximization()
#Call the solver
solv = solver.Solve()
#Print the results
if solv == pywraplp.Solver.OPTIMAL:
print('Total Packed Value:', objective.Value())
total_Sell = 0
for j in data['bags']:
bag_Sell = 0
avg_margin= 0
count = 0
print('\n','Bag', j+1 , '\n')
for i in data['items']:
if x[i,j].solution_value()>0:
print('Selected:', i ,
'Sell', data['sell'][i],
'margin',data['margin'][i],
)
bag_Sell += data['sell'][i]
avg_margin += data['margin'][i]
count += 1
print('Packed Knapsack Sell: ', bag_Sell)
print('Avg Packed Knapsack margin: ', round(avg_margin / count, 2))
print(f'Target Margin {data["target_margin"][0]} (Min {min_acceptable_margin} Max {max_acceptable_margin})')
else:
print("There is no optimal solution")
当我用上面的数字运行时,我得到了以下结果:
Total Packed Value: 9109.0
Bag 1
Selected: 7 Sell 4954 margin 25
Selected: 9 Sell 620 margin 25
Selected: 11 Sell 3260 margin 20
Selected: 12 Sell 75 margin 100
Selected: 13 Sell 200 margin 27
Packed Knapsack Sell: 9109
Avg Packed Knapsack margin: 39.4
Target Margin 40 (Min 38.0 Max 42.0)
调试时的有用命令
一些方便的命令可以帮助您调试 LP:
print('Number of variables =', solver.NumVariables())
print('Number of constraints =', solver.NumConstraints())
最后,最后一个非常有用的技巧。把求解器看到的公式写出来就好了。
#Use this to print out the ORTOOLS Formulation
print(solver.ExportModelAsLpFormat(False).replace('\', '').replace(',_', ','), sep='\n')
希望能帮助您前进。