2012-03-26 204 views
21

我正在尋找一個scipy/numpy內的優化程序,它可以解決非線性最小二乘類型問題(例如,將參數函數擬合到大型數據集),但包括邊界和約束條件(例如,要優化的參數的最小值和最大值)。目前我使用的是mpfit的python版本(翻譯自idl ...):這顯然不是最佳的,雖然它工作得很好。scipy.optimize.leastsq有約束約束

python/scipy/etc中的一個高效的例程可能非常棒! 任何輸入是非常歡迎這裏:-)

謝謝!

回答

9

scipy在scipy.optimize中有幾個constrained optimization routines。受限最小二乘變體是scipy.optimize.fmin_slsqp

+0

謝謝!將在未來幾天測試這個對mpfit我的問題,並會盡快報告! – user1293231 2012-03-26 22:19:31

+0

剛剛試過slsqp。我可能沒有正確使用它,但基本上它沒有太大的好處。當使用太低的epsilon值時,似乎會崩潰。否則,不會改變我的輸入參數中的任何內容(或差不多)。我會做一些調試,但看起來並不那麼容易使用(到目前爲止)。將進一步嘗試。 – user1293231 2012-04-03 12:41:11

+0

事實上,我只是得到以下錯誤==> linesearch的正方向派生(退出模式8)。這就是爲什麼我沒有得到任何地方....不是很有用。任何提示? – user1293231 2012-04-03 13:14:46

20

scipy.optimize.least_squares in scipy 0.17(2016年1月) 句柄bounds;使用,而不是這個黑客。


束縛約束可以容易地進行二次, 並通過leastsq與其餘部分一起最小化。假設你想最小化10個方塊的總和,所以你的func(p)是一個10-矢量[f0(p)... f9(p)],
想要0 < = p_i < = 1的3個參數。
考慮「桶功能」最大( - p,0,p - 1), 這是0內部0和外部正面,像一個\ _____ /浴缸。
如果我們給leastsq 13長的矢量

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

與W =說100,這將減少很多的平方和: 桶裏將制約0 < = P < = 1 一般lo < = p < = hi是類似的。
下面的代碼僅僅是一個包裝,其運行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 
+0

我已經收到這個錯誤,當我試圖實現它(Python 2.7):'文件「[/ PHPF]」,至少49行, ) 文件「[...]/minpack.py」,第369行,最小格數 shape,dtype = _check_func('leastsq','func',func,x0,args,n) File「[... ])/minpack.py「,第20行,在_check_func中 res = atleast_1d(thefunc(*((x0 [:numinputs]),+ args))) TypeError:()只需要1個參數(給出5)' – 2015-01-08 11:19:57

+1

@f_ficarola,對不起,args =是越野車;請剪切/粘貼並再次嘗試 – denis 2015-01-08 16:03:46

+0

感謝您的快速回復,denis。然而,在此期間,我發現了這個:'scipy.optimize.minimize(residualsModel,x0,args =(arg1,arg2,...),method ='SLSQP',bounds = [(xmin,xmax)] )'。你的代碼有什麼不同嗎? – 2015-01-08 18:40:28

3

看一看: http://lmfit.github.io/lmfit-py/,它應該解決您的問題。

+0

感謝您的提示:一個問題是,我希望能夠有一個自洽的Python模塊,包括有界非線性最小平方部分。這意味着要麼用戶將不得不安裝lmfit,要麼我將整個軟件包包含在我的模塊中。我將首先嚐試fmin_slsqp,因爲這是一個已經集成在scipy中的函數。但lmfit似乎正是我所需要的! – user1293231 2012-04-01 11:28:57

+0

考慮到您已經依賴SciPy,它不在標準庫中。 lmfit在pypi上,對大多數用戶來說應該很容易安裝。 – chthonicdaemon 2015-01-10 15:56:06

+0

鏈接已損壞! – denfromufa 2016-10-18 22:21:39

4

長久以來,Scipy一直缺乏以最佳方式解決非線性最小二乘問題的能力,如mpfit所做的那樣。

這個功能強大的功能終於在Scipy 0.17中引入,並且新功能scipy.optimize.least_squares

這個新函數可以使用合適的信賴域算法來處理約束約束,並優化使用非線性函數的平方和性質。

注:

通過@denis提出的解決方案具有引入不連續的「浴盆功能」的重大問題。這會導致爲平滑函數設計的scipy.optimize.leastsq優化,效率非常低,並且可能不穩定,當邊界交叉時。

採用scipy.optimize.minimizemethod='SLSQP'(如@f_ficarola建議的)或scipy.optimize.fmin_slsqp(如@馬特建議的),必須被最小化不利用的功能的平方和的-性質的主要問題。這些函數都是爲了儘量減少標量函數而設計的(儘管誤導性名稱也適用於fmin_slsqp)。這些方法效率較低,並且不如適當的方法準確。