5

私は最近、ある問題に時間を費やしました。私は一連のデータを持っています:

y = f(t)、ここで y は非常に小さい濃度 (10^-7)、t は秒です。t は 0 から約 12000 まで変化します。

測定値は確立されたモデルに従います。

y = Vs * t - ((Vs - Vi) * (1 - np.exp(-k * t)) / k)

そして、Vs、Vi、および k を見つける必要があります。そこで、最適なフィッティング パラメータを返すcurve_fitを使用して、曲線をプロットしました。

そして、同様のモデルを使用しました:

y = (Vs * t/3600 - ((Vs - Vi) * (1 - np.exp(-k * t/3600)) / k)) * 10**7

そうすることで、t は時間数、y は 0 から約 10 の間の数になります。返されるパラメーターはもちろん異なります。しかし、各曲線をプロットすると、次のようになります。

http://i.imgur.com/XLa4LtL.png

緑色のフィットは最初のモデルで、青色のフィットは「正規化された」モデルです。赤い点は実験値です。

フィッティングカーブが異なります。想定外だと思いますが、その理由がわかりません。数値が「合理的」である場合、計算はより正確になりますか?

4

3 に答える 3

5

ドキュメント文字列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):

したがって、既定では、許容誤差ftolxtolは 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 倍以上あることを示しています。したがって、他のすべてが等しい場合、非常に大きな数よりも小さな数を扱う方が、通常、より正確な答えが得られます。

于 2013-09-06T17:49:19.427 に答える
2

カーブ フィットに渡す初期パラメーター推定値と関係があると思います。何も渡していない場合は、すべてデフォルトで 1 になると思います。データを正規化すると、これらの初期推定値が真実に近づきます。正規化されたデータを使用したくない場合は、最初の見積もりを自分で渡し、妥当な値を指定してください。

于 2013-09-06T17:45:27.427 に答える