教程 > SciPy 教程 > SciPy 教程 阅读:490

SciPy Optimize 优化

scipy.optimize包提供了几个常用的优化算法。该模块包含以下方面:

  • 使用各种算法(例如 BFGS、Nelder-Mead simplex、Newton Conjugate Gradient、COBYLA 或 SLSQP)对多元标量函数(minimize())进行无约束和有约束的最小化
  • 全局优化例程(例如,anneal()、basinhopping())
  • 最小二乘最小化 (leastsq()) 和曲线拟合 (curve_fit()) 算法
  • 标量单变量函数最小化器 (minimize_scalar()) 和根查找器 (newton())
  • 多元方程系统求解器 (root()) 使用多种算法(例如混合 Powell、Levenberg-Marquardt 或 Newton-Krylov 等大规模方法)

多元标量函数的无约束和有约束最小化

minimize() 函数为 scipy.optimize 中的多元标量函数的无约束和约束最小化算法提供了一个通用接口。为了证明极小化函数,考虑最小化神经网络变量的RoxBoffk函数的问题。

xi = 1 时,此函数的最小值为 0。

Nelder-Mead 单纯形算法

在以下示例中,minimize() 例程与 Nelder-Mead 单纯形算法(method = 'Nelder-Mead')(通过 method 参数选择使用什么算法)一起使用。

from scipy.optimize import minimize
import numpy as np

# 计算 1/x+x 的最小值
def fun(args):
    a = args
    v = lambda x: a / x[0] + x[0]
    return v


if __name__ == "__main__":
    args = (1)  # a
    x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
    res = minimize(fun(args), x0, method='nelder-mead')
    print(res.fun)
    print(res.success)
    print(res.x)

运行示例

上面代码执行结果如下

2.000000000070772
True
[1.00000841 0.74890154 0.84872922 1.96128047 1.22306886]

单纯形算法可能是最小化性能相当好的函数的最简单方法。它只需要函数求值,对于简单的最小化问题是一个很好的选择。但是,由于它不使用任何梯度计算,因此可能需要更长的时间才能找到最小值。

另一种只需要函数调用即可找到最小值的优化算法是Powell 方法,可通过在 minimum () 函数中设置 method = 'powell' 来实现。

最小二乘法

求解具有变量边界的非线性最小二乘问题。给定残差 f(x)(n 个实变量的 m 维实函数)和损失函数 rho(s)(标量函数),least_squares 找到成本函数 F(x) 的局部最小值。

我们在自变量上找到没有边界的 Rosenbrock 函数的最小值。

import numpy as np
from scipy.optimize import least_squares


def fun_rosenbrock(x):
    return np.array([10 * (x[1] - x[0] ** 2), (1 - x[0])])


input = np.array([2, 2])
res = least_squares(fun_rosenbrock, input)

print(res)

运行示例

上述代码执行结果如下

active_mask: array([0., 0.])
        cost: 9.866924291084687e-30
         fun: array([4.44089210e-15, 1.11022302e-16])
        grad: array([-8.89288649e-14,  4.44089210e-14])
         jac: array([[-20.00000015,  10.        ],
       [ -1.        ,   0.        ]])
     message: '`gtol` termination condition is satisfied.'
        nfev: 3
        njev: 3
  optimality: 8.892886493421953e-14
      status: 1
     success: True
           x: array([1., 1.])

请注意,我们只提供残差的向量。该算法将成本函数构造为残差的平方和,这给出了 Rosenbrock 函数。确切的最小值是 x = [1.0,1.0]。


Root 查找

下面让我们看一下在SciPy中是如何进行根计算的。

标量函数

如果有一个单变量方程,有四种不同的求根算法可以尝试。这些算法中的每一个都需要期望根的区间的端点(因为函数会改变符号)。一般来说,brentq是最好的选择,但其他方法在某些情况下或用于学术目的可能更有用。

定点求解

与寻找函数的零点密切相关的问题是寻找函数的不动点的问题。函数的不动点是函数求值返回点的点:g(x) = x。显然,gg的不动点是 f(x) = g(x)−x 的根。等价地,ff的根是 g(x) = f(x)+x 的固定点。如果给定了起点,则例程 fixed_point 提供了一种简单的迭代方法,使用Aitkens 序列加速度来估计gg的不动点。

方程组

使用root() 函数可以找到一组非线性方程的根。有几种方法可用,其中hybr(默认)和 lm 分别使用Powell的hybrid方法和MINPACK的Levenberg-Marquardt方法

我们看下面的方程

x2 + 2cos(x) = 0

可以使用以下的代码找到其根

import numpy as np
from scipy.optimize import root

def func(x):
    return x * 2 + 2 * np.cos(x)

sol = root(func, 0.3)
print(sol)

运行示例

上述代码执行结果如下

fjac: array([[-1.]])
     fun: array([2.22044605e-16])
 message: 'The solution converged.'
    nfev: 10
     qtf: array([-2.77644574e-12])
       r: array([-3.34722409])
  status: 1
 success: True
       x: array([-0.73908513])

查看笔记

扫码一下
查看教程更方便