(几天前我发布了一个类似的问题,但是鉴于上一篇文章中的答案,我改变了方法,但使用了不同的方法)
我正在尝试使用scipy.optimize解决我的优化问题,但是我一直得到一个错误的答案,它只是返回我的初始猜测(x0)。在这里,我使用的是dual_annealing算法,但是我也尝试了不同的全局优化算法(differential_evolution,shgo)以及局部最小化(使用方法SLSQP进行最小化,但是由于我的函数没有梯度,所以这引起了问题)但是没有有用。
对于上下文,该程序正在尝试找到在多个商店中分配某些产品的最佳方法。每个商店都对接下来几天的预期销售量进行了预测(sales_data)。此预测不一定必须是整数或大于1(很少是),这是统计意义上的期望。因此,如果一家商店的sales_data = [0.33,0.33,0.33],则预计在3天后,他们将出售1件产品。
我想最大程度地减少出售我分配的单位所需的总时间(我想以最快的速度出售它们),而我的限制是我必须分配我有空的单位,而我不能分配负数商店产品的数量。我现在可以使用非整数分配。对于我的初始分配,我将在所有商店中平均分配可用的单位。
因此,以一种更数学的方式陈述,我希望最大化time_objective函数,但要满足所有分配必须为非负值(min(allocations)> = 0)并且必须分配的约束。所有可用单位(总和(分配)== unitsAvailable)。由于dual_annealing不支持约束,因此我通过为每个分配将0分配为下限来处理第一个约束(而unitsAvailable为上限)。对于第二个约束,我将目标函数包装在constrained_objective函数中,如果违反约束,该函数将返回numpy.inf。这个constrained_objective函数还接受除最后一个分配之外的所有分配,并将最后一个分配设置为其余单位(因为这等效于约束所有分配,但是不需要分配的总和恰好是unitAvailable)。
这是我的代码:
import numpy
import scipy.optimize as spo
unitsAvailable = 10
days = 50
class Store:
def __init__(self, num):
self.num = num
self.sales_data = []
# Mock Data
stores = []
for i in range(10):
# Identifier
stores.append(Store(i))
# Expected units to be sold that day (It's unlikey they will sell 1 every day)
stores[i].sales_data = [(i % 10) / 10 for x in range(days)]
def days_to_turn(alloc, store):
day = 0
inventory = alloc
while (inventory > 0 and day < days):
inventory -= store.sales_data[day]
day += 1
return day
def time_objective(allocations):
time = 0
for i in range(len(stores)):
time = max(time, days_to_turn(allocations[i], stores[i]))
return time
def constrained_objective(partial_allocs):
if numpy.sum(partial_allocs) > unitsAvailable:
# can't sell more than is available, so make the objective infeasible
return numpy.inf
# Partial_alloc contains allocations to all but one store.
# The final store gets allocated the remaining units.
allocs = numpy.append(partial_allocs, unitsAvailable - numpy.sum(partial_allocs))
return time_objective(allocs)
# Initial guess (x0)
guess_allocs = []
for i in range(len(stores)):
guess_allocs.append(unitsAvailable / len(stores))
guess_allocs = numpy.array(guess_allocs)
print('Optimizing...')
bounds = [(0, unitsAvailable)] * (len(stores))
time_solution = spo.dual_annealing(constrained_objective, bounds[:-1], x0=guess_allocs[:-1])
allocs = numpy.append(time_solution.x, unitsAvailable - numpy.sum(time_solution.x))
print("Allocations: " + str(allocs))
print("Days to turn: " + str(time_solution.fun))