尽管 x0 在范围内,Scipy 优化仍会引发 ValueError

问题描述 投票:0回答:2

我正在尝试将 S 形曲线拟合到一小组点上,基本上从一组观察结果生成一条概率曲线。我正在使用

scipy.optimize.curve_fit
,并稍微修改了逻辑函数(以便完全绑定在 [0,1] 内)。目前,我使用 Dogbox 方法和精确的 tr_solver 取得了最大的成功。

当我尝试运行代码时,对于某些数据点,它将引发:

ValueError: `x0` violates bound constraints.

我没有遇到这个问题(使用相同的代码和数据),直到我更新到最新版本的 numpy/scipy (numpy 1.17.0,scipy 1.3.1),所以我相信这是这个的结果更新(我无法降级,因为该项目其他方面所需的其他库需要这些版本)

我在一个大型数据集(N ~15000)上运行它,对于非常具体的值,曲线拟合失败,声称初始猜测超出了边界约束。事实并非如此,甚至在提供的示例中的曲线拟合之前通过打印语句快速检查也证实了这一点。

起初我以为这是一个 numpy 精度错误,这么小的值被认为是越界,但稍微改变它或提供一个新的、类似大小的任意数字不会导致 ValueError。此外,其他失败的值大到~1e-10,所以我认为它一定是其他东西。

这是一个每次对我来说都失败的例子:

import numpy as np
import scipy as sp
from scipy.special import expit, logit
import scipy.optimize

def f(x,x0,g,c,k):
    y = c*expit(k*10.*(x-x0)) + g*(1.-c)
    return y

#               x0                      g                       c                       k
p0 = np.array([8.841357069490852e-01, 4.492363462957287e-19, 5.547073496706608e-01, 7.435378446218519e+00])
bounds = np.array([[-1.,1.], [0.,1.], [0.,1.], [0.,20.]])
x = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 0.8911796599834791, 1.0, 1.0, 1.0, 0.33232919909076103, 1.0])
y = np.array([0.999, 0.999, 0.999, 0.999, 0.999, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001])
s = np.array([0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9])

print([pval >= b[0] and pval <= b[1] for pval,b in zip(p0,bounds)])

fit,cov = sp.optimize.curve_fit(f,x,y,p0=p0,sigma=s,bounds=([b[0] for b in bounds],[b[1] for b in bounds]),method='dogbox',tr_solver='exact')

print(fit)
print(cov)

这是具体的错误堆栈,上面调用曲线拟合之后的所有内容。

File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\minpack.py", line 763, in curve_fit
  **kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\_lsq\least_squares.py", line 927, in least_squares
  tr_solver, tr_options, verbose)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\_lsq\dogbox.py", line 310, in dogbox
  J = jac(x, f)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\_lsq\least_squares.py", line 874, in jac_wrapped
  kwargs=kwargs, sparsity=jac_sparsity)
File "C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\_numdiff.py", line 362, in approx_derivative
  raise ValueError("`x0` violates bound constraints.")
ValueError: `x0` violates bound constraints.

如果有人对可能导致此问题的原因有任何见解,我将非常感谢您的帮助!我做了一些搜索,但找不到任何可能与此场景相关的答案,因此我决定提出这个问题。谢谢!

编辑 2019 年 9 月 9 日:

np.__version__
是1.17.2,
sp.__version__
是1.3.1,当我最初发布这篇文章时,我使用的是numpy 1.17.0,但升级并没有解决问题。我在 64 位 Windows 10 上的 Python 3.6.6 上运行它。

如果我将第二个或第四个边界更改为+/-np.inf(或更改两者),那么代码实际上完成了——但我仍然不确定我的x0如何无效(并且我仍然需要有拟合限于这些值)

编辑:2020 年 1 月 22 日 将

np.__version__
升级到 1.18.1,将
sp.__version__
升级到 1.4.1,但无济于事。我已经在 scipy github 存储库上针对此错误打开了 an issues 。然而,他们似乎也无法重现该问题,因此无法解决它。

python numpy scipy curve-fitting least-squares
2个回答
0
投票
可怕的黑客行为。不要在家里这样做:)但如果您只是需要完成工作,则需要您自担风险:

C:\Users\user\AppData\Local\Programs\Python\Python36\lib\site-packages\scipy\optimize\_numdiff.py



找到:

if np.any((x0 < lb) | (x0 > ub)): raise ValueError("`x0` violates bound constraints.")
替换为:

if np.any(((x0 - lb) < -1e-12) | (x0 > ub)): raise ValueError("`x0` violates bound constraints.")
其中 

-1e-12

 是您认为您的案例可以容忍的边界约束错误 
(x0-lb) < 0
。这里 
x0
 是猜测,
lb
 是下限。

我不知道这次黑客攻击会造成什么可怕的数字。但如果你只是想开始......


0
投票
我也无法重现这个错误,但只要看看代码,我就可以说这不是一个规模很好的问题。参数

g

 比所有其他参数小得多。处理不同规模的参数对于任何优化算法来说都是一个挑战。通常的方法是将问题重新参数化为例如
log(g)
 或引入恒定缩放因子,例如 
g = factor * g_tilde
factor = 1e-19
。我相当乐观这会解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.