微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Scipy.minimize - 如何同时最小化两个函数

如何解决Scipy.minimize - 如何同时最小化两个函数

我需要优化不同底物与不同产品的混合。每种底物的量应加在一起以达到产品的 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))
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,bounds=bnds)
y = res.x
print(y)

解决方法

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

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.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()))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。