【问题标题】:scipy.optimize.leastsq with bound constraintsscipy.optimize.leastsq 有界约束
【发布时间】:2012-04-10 08:04:14
【问题描述】:

我正在寻找 scipy/numpy 中的优化例程,它可以解决非线性最小二乘类型问题(例如,将参数函数拟合到大型数据集),但包括边界和约束(例如,最小值和最大值)待优化参数)。目前我正在使用 mpfit 的 python 版本(从 idl 翻译...):这显然不是最佳的,虽然它工作得很好。

python/scipy/etc 中的高效例程可能会很棒! 这里非常欢迎任何意见:-)

谢谢!

【问题讨论】:

    标签: python optimization scipy mathematical-optimization


    【解决方案1】:

    scipy 在 scipy.optimize 中有几个 constrained optimization routines。受约束的最小二乘变体是scipy.optimize.fmin_slsqp

    【讨论】:

    • 谢谢!将在未来几天针对我的问题测试此与 mpfit 并尽快报告!
    • 刚试过slsqp。我可能没有正确使用它,但基本上它没有多大用处。当使用太低的 epsilon 值时,它似乎确实会崩溃。否则不会改变我的输入参数中的任何东西(或几乎)。我会做一些调试,但看起来它不是那么容易使用(到目前为止)。将进一步尝试。
    • 事实上我只是得到以下错误 ==> 线搜索的正方向导数(退出模式 8)。这就是为什么我没有得到任何地方......不是很有用。有什么提示吗?
    • 你能让它解决一个简单的问题吗,比如拟合 y = mx + b + 噪声? scipy.org/Cookbook/FittingData 是一个相当全面的 scipy.optimize 之旅,并有示例。
    【解决方案2】:

    scipy.optimize.least_squares 在 scipy 0.17 中(2016 年 1 月) 处理边界;使用它,而不是这个 hack。


    有界约束可以很容易地变成二次的, 并由 leastsq 与其余部分一起最小化。
    假设您要最小化 10 个平方和 Σ f_i(p)^2, 所以你的 func(p) 是一个 10 向量 [f0(p) ... f9(p)],
    并且还希望 0 考虑“浴缸函数” max( - p, 0, p - 1 ), 这是 0 内 0 .. 1 和正外,就像一个 \_____/ 浴缸。
    如果我们给leastsq 13 长的向量

    [ f0(p), f1(p), ... f9(p), w*tub(p0), w*tub(p1), w*tub(p2) ]
    

    如果 w = 100,它将最小化手数的平方和: 浴缸将约束 0 以下代码只是运行leastsq 的包装器 与例如这样一个 13 长的向量要最小化。

    # leastsq_bounds.py
    # see also test_leastsq_bounds.py on gist.github.com/denis-bz
    
    from __future__ import division
    import numpy as np
    from scipy.optimize import leastsq
    
    __version__ = "2015-01-10 jan  denis"  # orig 2012
    
    
    #...............................................................................
    def leastsq_bounds( func, x0, bounds, boundsweight=10, **kwargs ):
        """ leastsq with bound conatraints lo <= p <= hi
        run leastsq with additional constraints to minimize the sum of squares of
            [func(p) ...]
            + boundsweight * [max( lo_i - p_i, 0, p_i - hi_i ) ...]
    
        Parameters
        ----------
        func() : a list of function of parameters `p`, [err0 err1 ...]
        bounds : an n x 2 list or array `[[lo_0,hi_0], [lo_1, hi_1] ...]`.
            Use e.g. [0, inf]; do not use NaNs.
            A bound e.g. [2,2] pins that x_j == 2.
        boundsweight : weights the bounds constraints
        kwargs : keyword args passed on to leastsq
    
        Returns
        -------
        exactly as for leastsq,
    http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html
    
        Notes
        -----
        The bounds may not be met if boundsweight is too small;
        check that with e.g. check_bounds( p, bounds ) below.
    
        To access `x` in `func(p)`, `def func( p, x=xouter )`
        or make it global, or `self.x` in a class.
    
        There are quite a few methods for box constraints;
        you'll maybe sing a longer song ...
        Comments are welcome, test cases most welcome.
    
    """
        # Example: test_leastsq_bounds.py
    
        if bounds is not None  and  boundsweight > 0:
            check_bounds( x0, bounds )
            if "args" in kwargs:  # 8jan 2015
                args = kwargs["args"]
                del kwargs["args"]
            else:
                args = ()
    #...............................................................................
            funcbox = lambda p: \
                np.hstack(( func( p, *args ),
                            _inbox( p, bounds, boundsweight ))) 
        else:
            funcbox = func
        return leastsq( funcbox, x0, **kwargs )
    
    
    def _inbox( X, box, weight=1 ):
        """ -> [tub( Xj, loj, hij ) ... ]
            all 0  <=>  X in box, lo <= X <= hi
        """
        assert len(X) == len(box), \
            "len X %d != len box %d" % (len(X), len(box))
        return weight * np.array([
            np.fmax( lo - x, 0 ) + np.fmax( 0, x - hi )
                for x, (lo,hi) in zip( X, box )])
    
    # def tub( x, lo, hi ):
    #     """ \___/  down to lo, 0 lo .. hi, up from hi """
    #     return np.fmax( lo - x, 0 ) + np.fmax( 0, x - hi )
    
    #...............................................................................
    def check_bounds( X, box ):
        """ print Xj not in box, loj <= Xj <= hij
            return nr not in
        """
        nX, nbox = len(X), len(box)
        assert nX == nbox, \
            "len X %d != len box %d" % (nX, nbox)
        nnotin = 0
        for j, x, (lo,hi) in zip( range(nX), X, box ):
            if not (lo <= x <= hi):
                print "check_bounds: x[%d] %g is not in box %g .. %g" % (j, x, lo, hi)
                nnotin += 1
        return nnotin
    

    【讨论】:

    • 我在尝试实现它时收到了这个错误(python 2.7):File "[...]/leastsq_bounds.py", line 49, in leastsq_bounds return leastsq( funcbox, x0, **kwargs ) File "[...]/minpack.py", line 369, in leastsq shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) File "[...]/minpack.py", line 20, in _check_func res = atleast_1d(thefunc(*((x0[:numinputs],) + args))) TypeError: &lt;lambda&gt;() takes exactly 1 argument (5 given)
    • @f_ficarola,抱歉,args= 有问题;请剪切/粘贴并重试
    • 感谢您的快速回复,丹尼斯。但是,与此同时,我发现了这个:scipy.optimize.minimize(residualsModel, x0, args=(arg1, arg2, ...), method='SLSQP', bounds=[(xmin,xmax)])。你的代码有什么不同吗?
    • 无论如何,我现在收到一个不同的错误:File "leastsq_bounds.py", line 58, in leastsq_bounds return leastsq( funcbox, x0, **kwargs ) File "minpack.py", line 369, in leastsq shape, dtype = _check_func('leastsq', 'func', func, x0, args, n) File "minpack.py", line 20, in _check_func res = atleast_1d(thefunc(*((x0[:numinputs],) + args))) File "leastsq_bounds.py", line 55, in &lt;lambda&gt; _inbox( p, bounds, boundsweight ))) File "leastsq_bounds.py", line 66, in _inbox "len X %d != len box %d" % (len(X), len(box)) AssertionError: len X 1 != len box 2
    • @f_ficarola, 1) SLSQP 直接做边界(box bounds, == np.shape( bounds ) 是什么?它应该是 nparam x 2 -- 首先运行 leastsq_bounds.check_bounds( x0, bounds)
    【解决方案3】:

    看看: http://lmfit.github.io/lmfit-py/,应该可以解决你的问题。

    【讨论】:

    • 感谢您的提示:一个问题是我希望能够拥有一个自洽的 python 模块,包括有界的 non-lin 最小平方部分。这意味着要么用户也必须安装 lmfit,要么我将整个包包含在我的模块中。因此,我将首先尝试 fmin_slsqp,因为这是 scipy 中已经集成的功能。但 lmfit 似乎完全符合我的需要!
    • 请考虑您已经依赖 SciPy,它不在标准库中。 lmfit 在 pypi 上,对大多数用户来说应该很容易安装。
    • 链接已损坏!
    【解决方案4】:

    Scipy 长期以来一直缺少解决有界非线性最小二乘问题的能力,就像 mpfit 那样以最佳方式解决问题。

    这个备受追捧的功能终于在 Scipy 0.17 中引入了新功能scipy.optimize.least_squares

    这个新函数可以使用适当的信任域算法来处理有界约束,并充分利用非线性函数的平方和性质进行优化。

    注意事项:

    @denis 提出的解决方案的主要问题是引入了不连续的“桶函数”。这呈现了scipy.optimize.leastsq 优化,专为平滑函数而设计,当越界时效率非常低,并且可能不稳定。

    scipy.optimize.minimizemethod='SLSQP' (如@f_ficarola 建议)或scipy.optimize.fmin_slsqp(如@matt 建议)的使用,有一个主要问题是没有利用函数的平方和性质来被最小化。这些函数都旨在最小化标量函数(对于 fmin_slsqp 也是如此,尽管名称具有误导性)。这些方法的效率和准确性都低于适当的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 1970-01-01
      • 2019-09-29
      • 2019-10-07
      相关资源
      最近更新 更多