最小化一个简单的线性组合
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])
我知道这不是一件实际的事情(我提出这个问题只是为了让我能理解发生了什么),但我想知道为什么 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])