You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scipy Minimize未按预期调整优化变量问题求助

商品存储单次存取优化问题及解决方案

问题背景

我正在针对某商品的存储进行存、取日期优化,核心参数如下:

  • 存储最大容量:50百万英热单位(mm BBTUs)
  • 存/取速率:5百万英热单位/天
  • 存储成本:0.01百万美元/天
  • 商品价格:月度等间隔数据

先尝试单次存取优化,后续计划扩展为多次存取。

约束条件

  1. 取款日期 > 存款日期
  2. 总存入量 - 总取出量 < 50
  3. 存入量 = 取出量
  4. 日取出量 ≤5
  5. 日存入量 ≤5

利润函数

利润 = 取出量×取款日商品价格 - 存入量×存款日商品价格 - 成本×(取款日-存款日)

现有代码及问题

编写的Python代码如下:

##Volume in mm BBTUs
max_volume = 50
##Volume in mm BBTUs per day
rate = 5
##Cost in million dollars per day
costs = 0.01

commodity_prices = hw_nat_gas['Complete'].to_list()


from scipy.optimize import minimize


def constraint1(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates
    return withdrawal_date - deposit_date

# Define constraint function for volume constraint
def constraint_volume(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates  
    total_volume = volume_deposit - volume_withdrawal 
    return max_volume - total_volume 

def constraint_volume2(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates  
    return volume_deposit - volume_withdrawal

def profit_function(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = map(int, dates)
    profit = volume_withdrawal*commodity_prices[withdrawal_date] - volume_deposit*commodity_prices[deposit_date] - costs*(deposit_date-withdrawal_date)
    return -profit

def withdrawal(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = map(int, dates)
    return rate - volume_withdrawal

def deposit(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = map(int, dates)
    return rate - volume_deposit

constraints = [{'type': 'ineq', 'fun': constraint1},
               {'type': 'ineq', 'fun': constraint_volume},
               {'type': 'ineq', 'fun': withdrawal},
               {'type': 'ineq', 'fun': deposit},
               {'type': 'eq', 'fun' : constraint_volume2}]

bounds = [(0, 58), (0, 58), (0,5), (0,5)]

initial_guess = [7, 12, 0, 0]

result = minimize(profit_function, initial_guess, bounds=bounds, constraints=constraints)

遇到的问题:存、取日期及存、取量未按预期迭代优化,仅停留在初始猜测值;手动将初始猜测的存/取量设为5时利润会提升,但期望程序自动寻优。

解决建议

1. 移除强制类型转换,保留优化变量连续性

代码中map(int, dates)将连续优化变量强制转为整数,导致优化器无法进行梯度迭代,直接陷入初始值的局部最优。优化过程应保留变量连续性,仅在最终结果阶段做取整处理:

def profit_function(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates
    # 仅在索引价格时取整,优化过程保留变量连续
    profit = volume_withdrawal*commodity_prices[int(withdrawal_date)] - volume_deposit*commodity_prices[int(deposit_date)] - costs*(withdrawal_date - deposit_date)
    return -profit

def withdrawal(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates
    return rate - volume_withdrawal

def deposit(dates):
    deposit_date, withdrawal_date, volume_deposit, volume_withdrawal = dates
    return rate - volume_deposit

2. 修正利润函数的成本项符号

原代码成本项符号错误,存储天数是取款日-存款日,对应成本应为正的扣除项,修正后确保利润计算逻辑正确,避免优化器方向颠倒:

profit = volume_withdrawal*commodity_prices[int(withdrawal_date)] - volume_deposit*commodity_prices[int(deposit_date)] - costs*(withdrawal_date - deposit_date)

3. 调整初始猜测值

初始猜测的存/取量设为0时,优化器可能认为这是无损失的局部最优点。建议将初始值设为区间内合理值,给优化器明确的迭代起点:

initial_guess = [7, 12, 2.5, 2.5]

4. 选择适配的优化算法

默认L-BFGS-B算法处理带约束的混合变量优化能力有限,显式指定SLSQP算法(支持非线性约束),或针对整数日期需求使用混合整数规划工具scipy.optimize.milp:

# 显式指定SLSQP算法
result = minimize(profit_function, initial_guess, bounds=bounds, constraints=constraints, method='SLSQP')

若需严格整数日期优化,改用milp并标记日期变量为整数类型:

from scipy.optimize import milp, Bounds, LinearConstraint

# 定义变量类型:前两个为整数(日期),后两个为连续变量(存取量)
integrality = [1, 1, 0, 0]

# 转换为线性约束形式
constraints = [
    LinearConstraint([-1, 1, 0, 0], lb=1),  # 取款日期 > 存款日期(至少差1天)
    LinearConstraint([0, 0, 1, -1], ub=max_volume),  # 总存入量-总取出量 ≤50
    LinearConstraint([0, 0, 1, -1], lb=0, ub=0),  # 存入量=取出量
    LinearConstraint([0, 0, 0, 1], ub=rate),  # 日取出量 ≤5
    LinearConstraint([0, 0, 1, 0], ub=rate)   # 日存入量 ≤5
]

# 调用混合整数规划
result = milp(fun=lambda x: -profit_function(x), bounds=bounds, constraints=constraints, integrality=integrality)

5. 给约束添加微小松弛

可在不等式约束中添加微小的松弛值,避免优化器卡在边界无法迭代,例如将constraint1的返回值调整为withdrawal_date - deposit_date - 1e-3,确保严格大于的约束不会触发数值精度问题。

内容的提问来源于stack exchange,提问作者Arthur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 14:40:31