最小化一个简单的线性组合

Minimizing a simple Linear Combination

我知道这不是一件实际的事情(我提出这个问题只是为了让我能理解发生了什么),但我想知道为什么 SciPy 不能最小化以下线性组合(它 returns 初始权重并且只进行 1 次迭代):

from scipy.optimize import minimize
import numpy as np

mean = np.array([[0.00149066, 0.00076633]])

def constrain1(w):
    return w[0] + w[1] - 1

def minimize_func(w):
    return (w[0]*mean[0,0] + w[1]*mean[0,1])*(-1)


initial_guess = [0.5,0.5]
bound = (0,1)
bounds = [bound for i in range(2)]
con1 = {"type": "eq", "fun": constrain1}
cons = [con1]
sol = minimize(minimize_func, initial_guess,
               method="SLSQP", bounds=bounds, constraints=cons)

这里没有什么太神秘的了。 objective 函数并没有通过改变函数的参数得到太大改善。

minimize 以数值方式估计 objective 的一阶导数雅可比行列式。很容易看出这只是 -mean。但是,mean 中的值很小。并且考虑到参数总和为 1 的进一步限制,因此参数也必须很小,这意味着 minimize_func 的输出不会随着 minimize 搜索参数 space 而发生很大变化。也就是说,objective 在参数 space.

中非常相似

让我们具体一点。考虑一下 (0.5, 0.5) 的初始访客。这里的objective的值为:

>>> minimize_func((0.5, 0.5))
-0.001128495

minimize 将对这些参数进行小的扰动,并重新计算 objective,以确定这些更改是否会改善它。因为您没有指定任何曲率信息(Hessian 或二阶导数),函​​数选择启发式步长,在本例中为 1e-8。 (您可以通过在 objective 函数中打印 w 来查看。)

那么这对 objective 有多大影响?

>>> minimize_func((0.5, 0.5)) - minimize_func((0.5 + 1e-8, 0.5 - 1e-8))
7.243299926865121e-12

不幸的是,不多。这远低于此求解器的 default tolerance of 1e-6

我们可以看到,minimize 实际上会 通过指定较低的公差来执行进一步的迭代。

>>> minimize(minimize_func, (0.5, 0.5), method="SLSQP", bounds=bounds, constraints=cons, options={'disp': True}, tol=1e-8)
Optimization terminated successfully    (Exit mode 0)
            Current function value: -0.0014906599999999996
            Iterations: 7
            Function evaluations: 21
            Gradient evaluations: 7
     fun: -0.0014906599999999996
     jac: array([-0.00149066, -0.00076633])
 message: 'Optimization terminated successfully'
    nfev: 21
     nit: 7
    njev: 7
  status: 0
 success: True
       x: array([1.00000000e+00, 5.55111512e-16])