如何使用多个数组优化函数?

时间:2018-09-26 17:27:30

标签: python numpy optimization

给出数组abc

import numpy as np

a = np.array([100, 200, 300])
b = np.array([[1, 0, 0],
              [1, 0, 1],
              [0, 1, 1],
              [1, 1, 1]])
c = np.array([150, 300, 500, 650])

我想优化a,以使每个值都最小化c_prime中定义的绝对差之和。

c_prime = c - np.sum(a*b, axis=1)
print(c_prime)
print(np.abs(c_prime).sum())

[  50 -100    0   50]
200

手动...通过更改a中的第一个元素,c_prime开始获得所需的结果。

a = np.array([150, 200, 300])

c_prime = c - np.sum(a*b, axis=1)
print(c_prime)
print(np.abs(c_prime).sum())

[   0 -150    0    0]
150

现在,令人尴尬的是,我如何才能取得理想的结果? 我已经尝试过scipy.optimize.minimize,但是很明显,这段代码没有标记,该功能在概念上可能完全不正确。

def f(x, b, c):
    return np.abs(c - np.sum(x*b, axis=1)).sum()

x0 = a
minimize(f, x0, args=(b,c))

      fun: 200.0
 hess_inv: array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])
      jac: array([-1.,  0.,  1.])
  message: 'Desired error not necessarily achieved due to precision loss.'
     nfev: 327
      nit: 0
     njev: 63
   status: 2
  success: False
        x: array([100., 200., 300.])

鉴于从上面手动设置a[0]150所获得的改进结果,为什么这些结果返回非最优的x

1 个答案:

答案 0 :(得分:3)

这里的问题是您的目标函数不可微。 SciPy默认使用BFGS优化,这要求目标函数的一阶导数存在。

我可以想到3种解决此问题的主要方法:使用无导数优化,对目标函数使用微分逼近或将绝对值转换为约束。


scipy.optimize.minimize中的几乎所有优化方法都需要可微的目标函数。少数人没有,但是即使如此,也无法保证他们会找到最低要求。

例如,指定method='Nelder-Mead'会成功完成优化,并且在我的test run中指定x: array([ 149.99998103, 349.99999851, 150.00000599])的结果,但是正如Paul Panzer在评论中指出的那样,它从x0=[1, 1, 1]开始结果为convergence to a non-minimum。 Nelder-Mead有时只是这样做。即使目标函数具有微分,它也可以收敛到一个非平稳点。


目标函数的可微近似是容易的,并提供了更好的收敛性,但有一点误差。例如,将np.abs替换为

def pseudoabs(x):
    return (x**2+0.1)**0.5

results in convergencex: array([ 150.00000001, 350.00000011, 150.00000039]),使用默认的BFGS求解器。


关于将绝对值转换掉,您的问题几乎是一个标准的线性规划问题,但目标函数中包含绝对值。通过引入额外的变量,it's possible to convert an absolute value into two new linear constraints。想法是在约束|x|x'的约束下,用x' >= x项替换目标中的x' >= -x项。

这样做可以让您使用scipy.optimize.linprog之类的标准线性编程求解器解决问题,如果愿意,可以使用scipy.optimize.minimize来解决问题。


除此之外,可能还有其他算法可以解决这种形式的优化问题。我尝试按照“最小二乘最优化”的方式谷歌搜索“ l1最优化”,但结果却使最小化解向量的l1范数成为结果,这对这种情况是错误的向量。