SciPy - 优化

  • 简述

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

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

    minimize() function为多元标量函数的无约束和约束最小化算法提供了一个通用接口scipy.optimize. 为了演示最小化函数,考虑最小化 NN 变量的 Rosenbrock 函数的问题 -
    $$f(x) = \sum_{i = 1}^{N-1} \:100(x_i - x_{i-1}^{2})$$
    该函数的最小值为 0,当 xi = 1 时实现。
  • Nelder-Mead 单纯形算法

    在下面的示例中,minimize() 例程与Nelder-Mead simplex algorithm (method = 'Nelder-Mead')(通过方法参数选择)。让我们考虑下面的例子。
    
    import numpy as np
    from scipy.optimize import minimize
    def rosen(x):
    x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
    res = minimize(rosen, x0, method='nelder-mead')
    print(res.x)
    
    上述程序将生成以下输出。
    
    [7.93700741e+54  -5.41692163e+53  6.28769150e+53  1.38050484e+55  -4.14751333e+54]
    
    单纯形算法可能是最小化行为良好的函数的最简单方法。它只需要函数评估,对于简单的最小化问题来说是一个不错的选择。但是,由于它不使用任何梯度评估,因此可能需要更长的时间才能找到最小值。
    另一种只需要函数调用即可找到最小值的优化算法是Powell‘s method,可以通过在 minimum() 函数中设置 method = 'powell' 来获得。
  • 最小二乘

    求解具有变量界限的非线性最小二乘问题。给定残差 f(x)(n 个实变量的 m 维实函数)和损失函数 rho(s)(标量函数),least_squares 找到成本函数 F(x) 的局部最小值。让我们考虑下面的例子。
    在这个例子中,我们找到了一个最小的 Rosenbrock 函数,没有自变量的界限。
    
    #Rosenbrock Function
    def fun_rosenbrock(x):
       return np.array([10 * (x[1] - x[0]**2), (1 - x[0])])
       
    from scipy.optimize import least_squares
    input = np.array([2, 2])
    res = least_squares(fun_rosenbrock, input)
    print res
    
    请注意,我们只提供残差的向量。该算法将成本函数构造为残差的平方和,从而给出 Rosenbrock 函数。确切的最小值在 x = [1.0,1.0] 处。
    上述程序将生成以下输出。
    
    active_mask: array([ 0., 0.])
          cost: 9.8669242910846867e-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.8928864934219529e-14
          status: 1
          success: True
             x: array([ 1., 1.])
    
  • 寻根

    让我们了解根查找如何在 SciPy 中发挥作用。

    标量函数

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

    定点求解

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

    方程组

    可以使用以下方法找到一组非线性方程的根root() function. 有几种方法可用,其中hybr(默认)和 lm,分别使用hybrid method of PowellLevenberg-Marquardt method从MINPACK。
    以下示例考虑单变量超越方程。

    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])