Scipy.minimize - 如何同时最小化两个函数
Scipy.minimize - How to minimize two functions at the same time
我需要优化不同底物与不同产品的混合。各底物的用量相加应使产品中C、P、N、Si各组分的最佳比例。
我需要从 4 个底物中找到 2 个产品的完美比例。
我可以单独优化函数,但我想将所有内容都放在一个目标函数中。
我尝试 return 不同的优化问题,但出现错误“objective 函数必须 return 标量”
希望有人能帮助我。
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)
我强烈建议使用 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.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
])
那么,你的objective函数可以写成
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)
或者,您可以将其编写为一个 objective 函数:
# 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()))
我需要优化不同底物与不同产品的混合。各底物的用量相加应使产品中C、P、N、Si各组分的最佳比例。 我需要从 4 个底物中找到 2 个产品的完美比例。 我可以单独优化函数,但我想将所有内容都放在一个目标函数中。
我尝试 return 不同的优化问题,但出现错误“objective 函数必须 return 标量”
希望有人能帮助我。
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)
我强烈建议使用 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.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
])
那么,你的objective函数可以写成
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)
或者,您可以将其编写为一个 objective 函数:
# 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()))