Scipy Minimize未按预期调整优化变量问题求助
商品存储单次存取优化问题及解决方案
问题背景
我正在针对某商品的存储进行存、取日期优化,核心参数如下:
- 存储最大容量:50百万英热单位(mm BBTUs)
- 存/取速率:5百万英热单位/天
- 存储成本:0.01百万美元/天
- 商品价格:月度等间隔数据
先尝试单次存取优化,后续计划扩展为多次存取。
约束条件
- 取款日期 > 存款日期
- 总存入量 - 总取出量 < 50
- 存入量 = 取出量
- 日取出量 ≤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
相关产品推荐
相关产品推荐

