Sup*_*cia 5 python numpy minimization
我想找到固定点的列表,它们的值和位置以及它们是最小值还是最大值。
我的功能看起来像:
import numpy as np
def func(x,y):
return (np.cos(x*10))**2 + (np.sin(y*10))**2
Run Code Online (Sandbox Code Playgroud)
这是我正在考虑使用的方法:
我实际上已经在Mathematica上做了类似的事情。我一次又一次地区分函数。我看一下一阶导数为0的点,计算它们的值和位置。然后,我在那些位置取二阶导数,并检查它们是最小值还是最大值。
我还想知道是否仅对x和y中的函数值进行2D数组化,并找到该数组的最大值和最小值。但这需要我知道如何精确地定义x和y网格,以可靠地捕获函数的行为
对于后一种情况下,我已经找到像某些方面这一个。
我只是想知道,哪种方法在效率,速度,准确性甚至Python的优雅方面更有意义?
小智 4
找到驻点列表、它们的值和位置,以及它们是最小值还是最大值。
这通常是一个无法解决的问题。方法 1(符号)适合于此,但对于复杂函数,驻点没有符号解(没有符号求解一般两个方程组的方法)。
对于像您的示例这样的简单函数,SymPy可以正常工作。这是查找驻点并根据 Hessian 特征值对它们进行分类的完整示例。
import sympy as sym
x, y = sym.symbols("x y")
f = sym.cos(x*10)**2 + sym.sin(y*10)**2
gradient = sym.derive_by_array(f, (x, y))
hessian = sym.Matrix(2, 2, sym.derive_by_array(gradient, (x, y)))
Run Code Online (Sandbox Code Playgroud)
到目前为止,Hessian 是一个 2 × 2 的符号矩阵:[[200*sin(10*x)**2 - 200*cos(10*x)**2, 0], [0, -200*sin(10*y)**2 + 200*cos(10*y)**2]]。接下来,我们通过等于零来找到驻点gradient,并将它们一一代入Hessian。
stationary_points = sym.solve(gradient, (x, y))
for p in stationary_points:
value = f.subs({x: p[0], y: p[1]})
hess = hessian.subs({x: p[0], y: p[1]})
eigenvals = hess.eigenvals()
if all(ev > 0 for ev in eigenvals):
print("Local minimum at {} with value {}".format(p, value))
elif all(ev < 0 for ev in eigenvals):
print("Local maximum at {} with value {}".format(p, value))
elif any(ev > 0 for ev in eigenvals) and any(ev < 0 for ev in eigenvals):
print("Saddle point at {} with value {}".format(p, value))
else:
print("Could not classify the stationary point at {} with value {}".format(p, value))
Run Code Online (Sandbox Code Playgroud)
最后一个子句是必要的,因为当 Hessian 矩阵只是半定时,我们无法判断那是哪种驻点(x**2 + y**4并且x**2 - y**4在 (0, 0) 处具有相同的 Hessian 矩阵但行为不同)。输出:
Saddle point at (0, 0) with value 1
Local maximum at (0, pi/20) with value 2
Saddle point at (0, pi/10) with value 1
Local maximum at (0, 3*pi/20) with value 2
Local minimum at (pi/20, 0) with value 0
Saddle point at (pi/20, pi/20) with value 1
Local minimum at (pi/20, pi/10) with value 0
Saddle point at (pi/20, 3*pi/20) with value 1
Saddle point at (pi/10, 0) with value 1
Local maximum at (pi/10, pi/20) with value 2
Saddle point at (pi/10, pi/10) with value 1
Local maximum at (pi/10, 3*pi/20) with value 2
Local minimum at (3*pi/20, 0) with value 0
Saddle point at (3*pi/20, pi/20) with value 1
Local minimum at (3*pi/20, pi/10) with value 0
Saddle point at (3*pi/20, 3*pi/20) with value 1
Run Code Online (Sandbox Code Playgroud)
显然,solve没有找到所有的解决方案(有无限多个)。考虑求解与求解集,但无论如何,处理无限多个解都是困难的。
SciPy 提供了很多数值最小化例程,包括蛮力(这是你的方法 2;通常它非常非常慢)。这些都是强大的方法,但请考虑以下几点。
minimize)可能会产生另一个最大值或最小值。尽管如此,您永远不会知道是否还有其他您尚未见过的极值。使用lambdify它可以将符号表达式转换为可传递给 SciPy 数值求解器的 Python 函数。
from scipy.optimize import fsolve
grad = sym.lambdify((x, y), gradient)
fsolve(lambda v: grad(v[0], v[1]), (1, 2))
Run Code Online (Sandbox Code Playgroud)
在本例中,这将返回某个驻点[0.9424778 , 2.04203522]。具体是哪一点取决于最初的猜测,即 (1, 2)。通常(但并非总是)您会得到接近最初猜测的解决方案。
这比直接最小化方法有一个优点,因为也可以检测鞍点。尽管如此,找到所有解决方案仍然很困难,因为每次运行都fsolve只能找到一个解决方案。
| 归档时间: |
|
| 查看次数: |
1514 次 |
| 最近记录: |