非線形最小二乗タイプの問題(たとえば、パラメトリック関数を大きなデータセットに適合させる)を解決できるscipy/numpy内の最適化ルーチンを探していますが、境界と制約(たとえば、パラメーターの最小値と最大値)最適化されています)。現時点では、python mpfitのバージョン(idl ...から変換))を使用しています。これは非常にうまく機能しますが、明らかに最適ではありません。
Python/scipy/etc内の効率的なルーチンは、すばらしいものになるでしょう。ここでの入力は大歓迎です:-)
ありがとう!
scipy.optimize.least_squares scipy 0.17(2016年1月)で境界を処理します。このハックではなく、それを使用してください。
拘束された制約は簡単に二次式にでき、残りと一緒にleastsqによって最小化できます。
10平方和Σf_i(p)^ 2を最小化したいので、func(p)は10ベクトルです[f0(p)... f9(p)]、
また、3つのパラメータに対して0 <= p_i <= 1が必要です。
「タブ関数」max(-p、0、p-1)を検討してください。これは、0 .. 1の内側は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
scipyには、scipy.optimizeにいくつかの 制約付き最適化ルーチン があります。制約付き最小二乗バリアントは scipy.optimize.fmin_slsqp です。
境界を持つ非線形最小二乗問題を、mpfitのように最適な方法で解く機能は、Scipyには長くありませんでした。
この要望の多かった機能が、Scipy 0.17でようやく導入され、新しい関数 scipy.optimize.least_squares が追加されました。
この新しい関数は、適切な信頼領域アルゴリズムを使用して境界制約を処理し、非線形関数の平方和の性質を最適に使用して最適化します。
注:
@denisによって提案されたソリューションには、不連続な「タブ関数」を導入するという大きな問題があります。これにより、scipy.optimize.leastsq
最適化。スムーズな機能のために設計されており、非常に非効率的で、境界を越えると不安定になる可能性があります。
の用法 scipy.optimize.minimize
とmethod='SLSQP'
(@f_ficarolaが示唆したとおり)またはscipy.optimize.fmin_slsqp
(@mattが示唆するように)、最小化される関数の二乗和の性質を利用しないという大きな問題があります。これらの関数は両方とも、スカラー関数を最小化するように設計されています(誤解を招く名前にもかかわらず、fmin_slsqpについても真です)。これらのアプローチは、適切なアプローチよりも効率が悪く、精度も低くなります。
http://lmfit.github.io/lmfit-py/ をご覧ください。問題が解決されるはずです。