函数最小值optimize.minimize
因为在生活中,人们总是希望幸福值或其它达到一个极值,比如做生意时希望成本最小,收入最大,所以在很多商业情境中,都会遇到求极值的情况。
minimize
求解函数的极小值(无约束)
scipy.optimize.minimize(fun, x0,
args=(), method=None,
jac=None, hess=None,
hessp=None, bounds=None,
constraints=(), tol=None,
callback=None, options=None)
fun
:可调用对象,待优化的函数。最开始的参数是待优化的自变量;后面的参数由args
给出x0
:自变量的初始迭代值args
:一个元组,提供给fun
的额外的参数method
:一个字符串,指定了最优化算法。可以为:'Nelder-Mead'
、'Powell'
、'CG'
、'BFGS'
、'Newton-CG'
、'L-BFGS-B'
、'TNC'
、'COBYLA'
、'SLSQP'
、'dogleg'
、'trust-ncg'
jac
:一个可调用对象(最开始的参数是待优化的自变量;后面的参数由args
给出),雅可比矩阵。只在CG/BFGS/Newton-CG/L-BFGS-B/TNC/SLSQP/dogleg/trust-ncg
算法中需要。如果jac
是个布尔值且为True
,则会假设fun
会返回梯度;如果是个布尔值且为False
,则雅可比矩阵会被自动推断(根据数值插值)。hess/hessp
:可调用对象(最开始的参数是待优化的自变量;后面的参数由args
给出),海森矩阵。只有Newton-CG/dogleg/trust-ncg
算法中需要。二者只需要给出一个就可以,如果给出了hess
,则忽略hessp
。如果二者都未提供,则海森矩阵自动推断bounds
:一个元组的序列,给定了每个自变量的取值范围。如果某个方向不限,则指定为None
。每个范围都是一个(min,max)
元组。constrants
:一个字典或者字典的序列,给出了约束条件。只在COBYLA/SLSQP
中使用。字典的键为:type
:给出了约束类型。如'eq'
代表相等;'ineq'
代表不等fun
:给出了约束函数jac
:给出了约束函数的雅可比矩阵(只用于SLSQP
)args
:一个序列,给出了传递给fun
和jac
的额外的参数
tol
:指定收敛阈值options
:一个字典,指定额外的条件。键为:maxiter
:一个整数,指定最大迭代次数disp
:一个布尔值。如果为True
,则打印收敛信息
callback
:一个可调用对象,用于在每次迭代之后调用。调用参数为x_k
,其中x_k
为当前的参数向量
返回值:返回一个OptimizeResult
对象。其重要属性为:
x
:最优解向量success
:一个布尔值,表示是否优化成功message
:描述了迭代终止的原因
因为
Scipy.optimize.minimize
提供的是最小化方法,所以最大化距离就相当于最小化距离的负数:在函数的前面添加一个负号
基本使用
假设我们要求解最小值的函数为: 则雅可比矩阵为: 则海森矩阵为: 于是有:
def fun(p):
x,y=p.tolist()#p 为数组,形状为 (2,)
return f(x,y)
def jac(p):
x,y=p.tolist()#p 为数组,形状为 (2,)
return np.array([df/dx,df/dy])
def hess(p):
x,y=p.tolist()#p 为数组,形状为 (2,)
return np.array([[ddf/dxx,ddf/dxdy],[ddf/dydx,ddf/dyy]])
案例 0
计算 的最小值
from scipy.optimize import minimize
import numpy as np
#demo 1
#计算 1/x+x 的最小值
def fun(x):
return 1/x + x
x0 = np.asarray((2)) # 初始猜测值
res = minimize(fun, x0, method='SLSQP')
print(res)
# 结果:
fun: 2.0000000815356342
jac: array([0.00057095])
message: 'Optimization terminated successfully.'
nfev: 19
nit: 6
njev: 6
status: 0
success: True
x: array([1.00028559])
案例 1
计算函数:
的最小值
雅可比矩阵为: 海森矩阵为:
def func(p):
x, y = p
return (1-x)**2 + 100*(y-x**2)**2
def jac(p):
x, y = p
return np.array([2*(x-1)+400*x*(x**2-y), 200*(y-x**2)])
def hess(p):
x, y = p
return np.array([
[400*(3*x**2-y)+2, -400*x],
[-400*x, 200]
])
result = opt.minimize(func, x0=[10, 10],
method='Newton-CG',
jac=jac,
hess=hess)
result
结果:
fun: 1.5507998929041444e-18
jac: array([ 4.09654832e-07, -2.05662731e-07])
message: 'Optimization terminated successfully.'
nfev: 83
nhev: 51
nit: 51
njev: 133
status: 0
success: True
x: array([1., 1.])
案例 2
计算 的最小值 的范围都在0.1到0.9 之间
from scipy.optimize import minimize
import numpy as np
# demo 2
#计算 (2+x1)/(1+x2) - 3*x1+4*x3 的最小值 x1,x2,x3的范围都在0.1到0.9 之间
def fun(args):
a,b,c,d=args
v=lambda x: (a+x[0])/(b+x[1]) -c*x[0]+d*x[2]
return v
def con(args):
# 约束条件 分为eq 和ineq
#eq表示 函数结果等于0 ; ineq 表示 表达式大于等于0
x1min, x1max, x2min, x2max,x3min,x3max = args
cons = ({'type': 'ineq', 'fun': lambda x: x[0] - x1min},\
{'type': 'ineq', 'fun': lambda x: -x[0] + x1max},\
{'type': 'ineq', 'fun': lambda x: x[1] - x2min},\
{'type': 'ineq', 'fun': lambda x: -x[1] + x2max},\
{'type': 'ineq', 'fun': lambda x: x[2] - x3min},\
{'type': 'ineq', 'fun': lambda x: -x[2] + x3max})
return cons
#定义常量值
args = (2,1,3,4) #a,b,c,d
#设置参数范围/约束条件
args1 = (0.1,0.9,0.1, 0.9,0.1,0.9) #x1min, x1max, x2min, x2max,x3min, x3max
cons = con(args1)
#设置初始猜测值
x0 = np.asarray((0.5,0.5,0.5))
res = minimize(fun(args), x0, method='SLSQP',constraints=cons)
结果:
fun: -0.773684210526435
jac: array([-2.47368421, -0.80332409, 4. ])
message: 'Optimization terminated successfully.'
nfev: 10
nit: 2
njev: 2
status: 0
success: True
x: array([0.9, 0.9, 0.1])