为什么scipy.optimize没有给我正确的答案?

时间:2019-08-13 20:23:08

标签: python optimization scipy scipy-optimize

(几天前我发布了一个类似的问题,但是鉴于上一篇文章中的答案,我改变了方法,但使用了不同的方法)

我正在尝试使用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))

0 个答案:

没有答案