使用scipy.optimize进行带边界的最小二乘优化

1 投票
2 回答
2001 浏览
提问于 2025-04-18 13:22

我有一个最小二乘优化的问题,需要一些帮助来解决。目前,我有一些代码可以完成以下功能:

shankarFunc = lambda p, x: p[0] * (1 - np.exp(-1 * ((x / p[1]) ** p[2])))
errFunc = lambda p, x, y: shankarFunc(p, x) - y

x0 = [max(y), 100 / max(y), 1]

p1, success = optimize.leastsq(errFunc, x0, args=(x, y))

这个功能在大多数情况下几乎能正常工作。不过,对于某些数据,它没有收敛,所以我需要进行带有参数范围的最小二乘拟合。我注意到 optimize.minimize 这个函数可以设置参数范围,于是我尝试用它来最小化误差函数。

shankarFunc = lambda p, x: p[0] * (1 - np.exp(-1 * ((x / p[1]) ** p[2])))
errFunc = lambda p, x, y: shankarFunc(p, x) - y

x0 = [max(y), 100 / max(y), 1]
b0 = (0, max(y) + 2)
b1 = (1e-4, 5)
b2 = (0, None)
p1 = optimize.minimize(errFunc, x0, args=(x, y), bounds=(b0, b1, b2))

但这给我带来了问题,因为它返回了以下错误:

  File "C:\Anaconda\lib\site-packages\scipy\optimize\optimize.py", line 610, in
approx_fprime
    grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
ValueError: setting an array element with a sequence.

我尝试了很多不同的输入组合,但始终无法解决这个问题。

我该如何让 optimize.minimize 正常工作呢?有没有更好的方法可以为解决方案添加参数范围?

2 个回答

1

在没有更多信息的情况下,我建议你尝试以下一些方法:

  • 你的 errFunc 是返回一个单一的数值,还是返回一个列表或数组呢?我也花了一些时间才让 scipy.optimize.minimize 正常工作,回头看我的代码,我的误差函数是返回一个单一的数值。

  • 明确指定优化方法,这样它就知道要使用边界,比如 method='L-BFGS-B'

2

minimize 是用来优化一个标量函数的,也就是说你需要返回一个数组(这是 leastsq 所期望的)。如果你想使用 minimize,可以试着把你的函数改成:

errFunc = lambda p, x, y: np.sum((shankarFunc(p, x) - y)**2)

你也可以使用 lmfit,网址是 http://lmfit.github.io/lmfit-py/,它允许通过变换来使用带限制的 leastsq。

撰写回答