Scipy.minimize使用教程:如何同时最小化两个函数实现基质配比优化
问题原因
scipy.optimize.minimize 要求目标函数必须返回单个标量的损失值,你之前尝试直接返回两个产物的独立损失值不符合接口要求,只要将两个损失相加合并为一个总损失即可解决问题。
另外补充一个代码里遗漏的逻辑:如果变量里存的是基质占比,需要添加约束条件保证产物1的4个基质占比之和为1,产物2的4个基质占比之和为1,否则优化结果没有实际意义。
完整修改后的代码
import numpy as np from scipy.optimize import minimize # 基质组分定义 class substrat_1: C = 0.93 N = 0.005 P = 0.031 Si = 0.034 class substrat_2: C = 0.523 N = 0.3 P = 0.123 Si = 0.054 class substrat_3: C = 0.257 N = 0.176 P = 0.461 Si = 0.106 class substrat_4: C = 0.694 N = 0.005 P = 0.003 Si = 0.298 # 产物目标组分定义 class sort_1: C = 0.7 N = 0.15 P = 0.05 Si = 0.1 class sort_2: C = 0.8 N = 0.03 P = 0.1 Si = 0.07 # 合并后的目标函数 def combined_target(y): # 计算产物1的组分偏差 s1_C = substrat_1.C*y[0] + substrat_2.C*y[1] + substrat_3.C*y[2] + substrat_4.C*y[3] s1_N = substrat_1.N*y[0] + substrat_2.N*y[1] + substrat_3.N*y[2] + substrat_4.N*y[3] s1_P = substrat_1.P*y[0] + substrat_2.P*y[1] + substrat_3.P*y[2] + substrat_4.P*y[3] s1_Si = substrat_1.Si*y[0] + substrat_2.Si*y[1] + substrat_3.Si*y[2] + substrat_4.Si*y[3] loss1 = np.abs(s1_C-sort_1.C) + np.abs(s1_N-sort_1.N) + np.abs(s1_P-sort_1.P) + np.abs(s1_Si-sort_1.Si) # 计算产物2的组分偏差 s2_C = substrat_1.C*y[4] + substrat_2.C*y[5] + substrat_3.C*y[6] + substrat_4.C*y[7] s2_N = substrat_1.N*y[4] + substrat_2.N*y[5] + substrat_3.N*y[6] + substrat_4.N*y[7] s2_P = substrat_1.P*y[4] + substrat_2.P*y[5] + substrat_3.P*y[6] + substrat_4.P*y[7] s2_Si = substrat_1.Si*y[4] + substrat_2.Si*y[5] + substrat_3.Si*y[6] + substrat_4.Si*y[7] loss2 = np.abs(s2_C-sort_2.C) + np.abs(s2_N-sort_2.N) + np.abs(s2_P-sort_2.P) + np.abs(s2_Si-sort_2.Si) # 合并为单值损失返回,可调整权重w1、w2侧重不同产物的优化精度 w1, w2 = 1, 1 return w1 * loss1 + w2 * loss2 # 约束条件:两个产物的基质占比之和都为1 cons = ( {'type': 'eq', 'fun': lambda y: np.sum(y[:4]) - 1}, {'type': 'eq', 'fun': lambda y: np.sum(y[4:]) - 1} ) # 变量边界:所有占比在0到1之间 bnds = ((0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1)) # 初始值 y0 = np.ones(8) / 4 # 执行优化 res = minimize(combined_target, x0=y0, method='SLSQP', bounds=bnds, constraints=cons) # 输出结果 print("优化得到的配比:") print(f"产物1的基质占比(基质1-4):{np.round(res.x[:4], 4)},总和:{np.round(np.sum(res.x[:4]), 4)}") print(f"产物2的基质占比(基质1-4):{np.round(res.x[4:], 4)},总和:{np.round(np.sum(res.x[4:]), 4)}") print(f"总损失值:{np.round(res.fun, 6)}")
说明
- 若需要优先保证某个产物的组分精度,调整目标函数里的
w1、w2权重即可,比如把w1设为2代表产物1的优化优先级是产物2的2倍。 - 如果你的y变量是基质的绝对用量而非占比,删除对应的约束条件即可。
内容的提问来源于stack exchange,提问作者mrgreen
相关产品推荐
相关产品推荐

