Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

3.2.4 计算全域最小值

前面介绍的几种最小值优化算法都只能计算局域的最小值,optimize库还提供了几种能进行全局优化的算法,下面以前面的正弦波拟合为例,演示全局优化函数的用法。在使用leastsq( )对正弦波进行拟合时,误差函数residuals( )返回一个数组,表示各个取样点的误差。而函数最小值算法则只能对一个标量值进行最小化,因此最小化的目标函数func_error( )返回所有取样点的误差的平方和。

    def func(x, p):
        A, k, theta = p
        return A*
np.sin(2*
np.pi*
k*
x+theta)
    
    def func_error(p, y, x):
        return np.sum((y - func(x, p))**
2)   
    
    x = np.linspace(0, 2*
np.pi, 100)
    A, k, theta = 10, 0.34, np.pi/6 
    y0 = func(x, [A, k, theta])
    np.random.seed(0)
    y1 = y0 + 2 *
 np.random.randn(len(x))

我们使用optimize.basinhopping( )全域优化函数找出正弦波的三个参数。它的前两个参数和其他求最小值的函数一样:目标函数和初始值。由于它是全局优化函数,因此初始值的选择并不是太重要。niter参数是全域优化算法的迭代次数,迭代的次数越多,就越有可能找到全域最优解。

在basinhopping( )内部需要调用局域最小值函数,其minimizer_kwargs参数决定了所采用的局域最小值算法以及传递给此函数的参数。下面的程序指定使用L-BFGS-B算法搜索局域最小值,并且将两个对象y1和x传递给该局域最小值求解函数的args参数,而该函数会将这两个参数传递给func_error( )。

    result = optimize.basinhopping(func_error, (1, 1, 1),
                          niter = 10,
                          minimizer_kwargs={"method":"L-BFGS-B",
                                            "args":(y1, x)})
    print result.x
    [ 10.25218694  -0.34239909   2.63341582]

虽然频率和相位与原系数不同,但是由于正弦函数的周期性,其拟合曲线是和原始数据重合的,如图3-5所示。

图3-5 用basinhopping( )拟合正弦波