のドキュメント文字列optimize.curve_fit
は、
p0 : None, scalar, or M-length sequence
Initial guess for the parameters. If None, then the initial
values will all be 1 (if the number of parameters for the function
can be determined using introspection, otherwise a ValueError
is raised).
したがって、まず、パラメーターの初期推定値はデフォルトで 1 です。
さらに、カーブ フィッティング アルゴリズムは、パラメータのさまざまな値について関数をサンプリングする必要があります。「さまざまな値」は、最初は 1 程度の初期ステップ サイズで選択されます。1 程度のパラメータ値の変化でデータがある程度滑らかに変化する場合、アルゴリズムはより適切に機能します。
パラメータの変化が 1 のオーダーで関数が大きく変化する場合、アルゴリズムは最適なパラメータ値を見逃す傾向があります。
アルゴリズムがパラメータ値を微調整するときに適応ステップ サイズを使用する場合でも、最初の微調整がマークから大きく外れて大きな残差が生成される場合、および他の方向への微調整によってたまたま小さな残差が生成される場合は、次のことに注意してください。アルゴリズムが間違った方向に迷い、極小値を見逃す可能性があります。他の (望ましくない) 局所的最小値が見つかるか、単に収束に失敗する可能性があります。したがって、適応ステップ サイズのアルゴリズムを使用しても、必ずしも節約できるわけではありません。
この話の教訓は、データをスケーリングすると、アルゴリズムが目的の最小値を見つける可能性が向上するということです。
一般に、数値アルゴリズムはすべて、大きさが 1 程度のデータに適用すると、より適切に機能する傾向があります。このバイアスは、さまざまな方法でアルゴリズムに入ります。たとえば、optimize.curve_fit
は に依存してoptimize.leastsq
おり、 の呼び出し署名optimize.leastsq
は次のとおりです。
def leastsq(func, x0, args=(), Dfun=None, full_output=0,
col_deriv=0, ftol=1.49012e-8, xtol=1.49012e-8,
gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None):
したがって、既定では、許容誤差ftol
とxtol
は 1e-8 のオーダーです。最適なパラメーター値を見つけるために必要な公差がはるかに小さい場合、これらのハードコーディングされたデフォルトの数値によりoptimize.curve_fit
、最適化パラメーター値が失われます。
これをより具体的にするために、 を最小化しようとしていたとしますf(x) = 1e-100*x**2
。1e-100 の係数は、-y
値を非常に押しつぶして、広範囲の-x
値 (上記のパラメーター値) が 1e-8 の許容範囲内に収まるようにします。したがって、非理想的なスケーリングでleastsq
は、最小値を見つけるのにうまくいきません。
1 のオーダーで float を使用するもう 1 つの理由は、1[-1,1]
から遠く離れているよりも多くの (IEEE754) float が間隔内にあるためです。たとえば、
import struct
def floats_between(x, y):
"""
http://stackoverflow.com/a/3587987/190597 (jsbueno)
"""
a = struct.pack("<dd", x, y)
b = struct.unpack("<qq", a)
return b[1] - b[0]
In [26]: floats_between(0,1) / float(floats_between(1e6,1e7))
Out[26]: 311.4397707054894
これは、間隔 [1e6, 1e7] にあるよりも、0 から 1 の間の数値を表す float が 300 倍以上あることを示しています。したがって、他のすべてが等しい場合、非常に大きな数よりも小さな数を扱う方が、通常、より正確な答えが得られます。