【问题标题】:Scipy.minimize - How to minimize two functions at the same timeScipy.minimize - 如何同时最小化两个函数
【发布时间】:2021-06-24 13:18:00
【问题描述】:

我需要针对不同产品优化不同基质的混合。每种底物的量应加在一起,使产品的组分 C、P、N、Si 达到最佳比例。 从 4 种基质中,我需要找到 2 种产品的完美比例。 我没有问题单独优化功能,但我想把所有东西都放在一个目标功能中。

我试图返回不同的优化问题,但我得到错误“目标函数必须返回一个标量”

我希望有人可以帮助我。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.optimize import fsolve

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

y[0] substrat_1 -> sort_1
y[1] substrat_2 -> sort_1
y[2] substrat_3 -> sort_1
y[3] substrat_4 -> sort_1
y[4] substrat_1 -> sort_2
y[5] substrat_2 -> sort_2
y[6] substrat_3 -> sort_2
y[7] substrat_4 -> sort_2

def targetFun1(y):
    amount_sort1_C = substrat_1.C*y[0] + substrat_2.C*y[1] + substrat_3.C*y[2] + substrat_4.C*y[3]
    amount_sort1_N = substrat_1.N*y[0] + substrat_2.N*y[1] + substrat_3.N*y[2] + substrat_4.N*y[3]
    amount_sort1_P = substrat_1.P*y[0] + substrat_2.P*y[1] + substrat_3.P*y[2] + substrat_4.P*y[3]
    amount_sort1_Si = substrat_1.Si*y[0] + substrat_2.Si*y[1] + substrat_3.Si*y[2] + substrat_4.Si*y[3]

    return (np.abs(amount_sort1_C-sort_1.C)+np.abs(amount_sort1_N-sort_1.N)+np.abs(amount_sort1_P-sort_1.P)+np.abs(amount_sort1_Si-sort_1.Si)) 

bnds=((0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1),(0,1))
y0 = np.zeros((8,))

res = minimize(targetFun1, x0 = y0, method='SLSQP', bounds=bnds) 
y = res.x
print(y)

def targetFun2(y):
    amount_sort2_C = substrat_1.C*y[4] + substrat_2.C*y[5] + substrat_3.C*y[6] + substrat_4.C*y[7]
    amount_sort2_N = substrat_1.N*y[4] + substrat_2.N*y[5] + substrat_3.N*y[6] + substrat_4.N*y[7]
    amount_sort2_P = substrat_1.P*y[4] + substrat_2.P*y[5] + substrat_3.P*y[6] + substrat_4.P*y[7]
    amount_sort2_Si = substrat_1.Si*y[4] + substrat_2.Si*y[5] + substrat_3.Si*y[6] + substrat_4.Si*y[7]
    
    return (np.abs(amount_sort2_C-sort_2.C)+np.abs(amount_sort2_N-sort_2.N)+np.abs(amount_sort2_P-sort_2.P)+np.abs(amount_sort2_Si-sort_2.Si))


res = minimize(targetFun2, x0 = y0, method='SLSQP', bounds=bnds)
y = res.x
print(y)

【问题讨论】:

  • 您的 targetFun1 返回一个标量,优化对我来说运行良好。你确定这是正确的例子吗?
  • 对不起,我忘了复制一些东西……使用第二个目标函数计算其他产品。你知道我如何将它们都添加到一个函数中并将结果保存在 4*2 矩阵中吗?

标签: python scipy-optimize scipy-optimize-minimize


【解决方案1】:

我强烈建议使用 np.ndarrays 而不是类来存储您的数据:

substrat = np.array([
    [0.93, 0.005, 0.031, 0.034],  # substrat_1
    [0.523, 0.3, 0.123, 0.054],   # substrat_2
    [0.257, 0.176, 0.461, 0.106], # substrat_3
    [0.694, 0.005, 0.003, 0.298], # substrat_4
])

sort = np.array([
    [0.7, 0.15, 0.05, 0.1], # sort_1
    [0.8, 0.03, 0.1, 0.07]  # sort_2
])

那么,你的目标函数可以写成

def targetFun1(y):
    return np.sum(np.abs(substrat.T @ y[:4] - sort[0]))

def targetFun2(y):
    return np.sum(np.abs(substrat.T @ y[4:] - sort[1]))

这里,.T 表示矩阵的转置/np.ndarray substrat@ 表示矩阵乘法运算符。 由于 0 是两个函数的下限,因此同时最小化两个函数的一种方法是最小化两个函数的总和:

res = minimize(lambda y: targetFun1(y) + targetFun2(y), x0 = y0, method='SLSQP', bounds=bnds)

# Finally, we only need to reshape the solution `res.x`:
solution = res.x.reshape(4,2)

或者,你可以把它写成一个目标函数:

# Create BlockDiagonalmatrix:
# ( substrat.T.  0          )
# (     0        substrat.T )
#
DiagSubstrat = np.kron(np.eye(2), substrat.T)

def targetFun(y):
    return np.sum(np.abs(DiagSubstrat @ y - sort.flatten()))

【讨论】:

  • 非常感谢您的建议。我将明确地调整数组。有没有办法将两个目标函数合二为一?
  • @mrgreen 当然,我编辑了我的答案。顺便说一句,如果我的回答有帮助,请考虑accepting and/or upvoting it
猜你喜欢
  • 2020-10-06
  • 1970-01-01
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多