使用scipy.minimize将4个独立目标函数合并为单个优化目标函数的方法
解决方案
你现有代码中通过lambda y: targetFun1(y) + targetFun2(y) + targetFun3(y) + targetFun4(y)的写法已经实现了四个目标函数求和合并的需求,如果想要减少冗余代码、提升可维护性,可以参考以下优化方案:
优化思路
- 将基质、目标产物的参数整理为numpy数组,避免定义大量重复的类
- 封装通用的单产物目标计算逻辑,不需要写4份几乎完全相同的函数
- 补充每类产物的4种基质占比之和为1的约束,保证配比结果符合实际意义(你现有代码缺失该约束,可能得到不合理的配比结果)
优化后代码
import numpy as np from scipy.optimize import minimize # 基质参数:4种基质,4种元素(C/N/P/Si) substrat = np.array([ [0.93, 0.005, 0.031, 0.034], # 基质1 [0.523, 0.3, 0.123, 0.054], # 基质2 [0.257, 0.176, 0.461, 0.106], # 基质3 [0.694, 0.005, 0.003, 0.298] # 基质4 ]) # 目标产物参数:4种产物,4种元素目标值 target_sort = np.array([ [0.7, 0.15, 0.05, 0.1], # 产物1 [0.8, 0.03, 0.1, 0.07], # 产物2 [0.4, 0.2, 0.1, 0.3], # 产物3 [0.5, 0.05, 0.3, 0.15] # 产物4 ]) def combined_target(y): # 将1维输入转为4行(4种产物)4列(4种基质占比)的数组 y_mat = y.reshape(4, 4) total_loss = 0 for i in range(4): # 计算第i种产物混合后的元素含量 mix_element = y_mat[i] @ substrat # 累加L1损失 total_loss += np.sum(np.abs(mix_element - target_sort[i])) return total_loss # 边界约束:所有占比在0~1之间 bnds = tuple((0, 1) for _ in range(16)) # 等式约束:每类产物的4种基质占比之和为1 cons = [{'type': 'eq', 'fun': lambda y: np.sum(y.reshape(4,4)[i]) - 1} for i in range(4)] # 初始值 y0 = np.ones((16,)) * 0.25 res = minimize(combined_target, x0=y0, method='SLSQP', bounds=bnds, constraints=cons) # 输出结果:每行对应一种产物的4种基质占比 y_result = res.x.reshape(4,4) print("配比结果(每行对应1种产物的4种基质占比):") print(np.round(y_result, 4)) # 验证每行和为1 print("每行占比求和验证:", np.sum(y_result, axis=1))
原代码问题说明
你原来的写法虽然可以运行,但因为没有加占比和为1的约束,优化出来的结果每类产物的基质占比总和可能不是1,不符合混合物配比的实际要求,补充约束后结果会更合理。
内容的提问来源于stack exchange,提问作者mrgreen
相关产品推荐
相关产品推荐

