簡體   English   中英

從Python SciPy curve_fit獲得更多優化結果

[英]Getting more refined results from Python SciPy curve_fit

我有以下Python(v2.7.14)代碼,它使用SciPy(v1.0.1)中的curve_fit查找指數衰減函數的參數。 大多數時候,我會得到合理的結果。 有時,盡管找到的參數相對於原始圖形繪制時看起來會很好,但我有時還是會得到一些超出預期范圍的結果。

首先,我對指數衰減公式的理解來自https://en.wikipedia.org/wiki/Exponential_decay ,我將其翻譯為Python:


y = a * numpy.exp(-b * x) + c

在哪里:

  • a是數據的初始值
  • b是衰減率,它是信號從初始值變為1 / e時的倒數
  • c是一個偏移量,因為我正在處理數據中永遠不會達到零的非負值
  • x是當前時間

該腳本考慮到要擬合非負數據,並適當地抵消了初始猜測。 但是,即使沒有猜測,也沒有使用最大/最小值(而不是第一個/最后一個值)和我嘗試過的其他隨機方法進行補償,我似乎也無法獲得curve_fit在麻煩的數據集上產生有意義的值。

我的假設是,麻煩的數據集沒有足夠的曲線可以擬合而不會超出數據范圍。 我查看了curve_fit的bounds參數,並認為這可能是一個合理的選擇。 我不確定什么將使計算的上下限更好,或者實際上是否是我正在尋找的選項。

這是代碼。 注釋掉的代碼是我嘗試過的事情。


#!/usr/local/bin/python

import numpy as numpy
from scipy.optimize import curve_fit
import matplotlib.pyplot as pyplot

def exponential_decay(x, a, b, c):
    return a * numpy.exp(-b * x) + c

def fit_exponential(decay_data, time_data, decay_time):
    # The start of the curve is offset by the last point, so subtract
    guess_a = decay_data[0] - decay_data[-1]
    #guess_a = max(decay_data) - min(decay_data)

    # The time that it takes for the signal to reach 1/e becomes guess_b
    guess_b = 1/decay_time

    # Since this is non-negative data, above 0, we use the last data point as the baseline (c)
    guess_c = decay_data[-1]
    #guess_c = min(decay_data)

    guess=[guess_a, guess_b, guess_c]
    print "guess: {0}".format(guess)

    #popt, pcov = curve_fit(exponential_decay, time_data, decay_data, maxfev=20000)
    popt, pcov = curve_fit(exponential_decay, time_data, decay_data, p0=guess, maxfev=20000)

    #bound_lower = [0.05, 0.05, 0.05]
    #bound_upper = [decay_data[0]*2, guess_b * 10, decay_data[-1]]
    #print "bound_lower: {0}".format(bound_lower)
    #print "bound_upper: {0}".format(bound_upper)
    #popt, pcov = curve_fit(exponential_decay, time_data, decay_data, p0=guess, bounds=[bound_lower, bound_upper], maxfev=20000)

    a, b, c = popt

    print "a: {0}".format(a)
    print "b: {0}".format(b)
    print "c: {0}".format(c)

    plot_fit = exponential_decay(time_data, a, b, c)

    pyplot.plot(time_data, decay_data, 'g', label='Data')
    pyplot.plot(time_data, plot_fit, 'r', label='Fit')
    pyplot.legend()
    pyplot.show()

print "Gives reasonable results"
time_data = numpy.array([0.0,0.040000000000000036,0.08100000000000018,0.12200000000000011,0.16200000000000014,0.20300000000000007,0.2430000000000001,0.28400000000000003,0.32400000000000007,0.365,0.405,0.44599999999999995,0.486,0.5269999999999999,0.567,0.6079999999999999,0.6490000000000002,0.6889999999999998,0.7300000000000002,0.7700000000000002,0.8110000000000002,0.8510000000000002,0.8920000000000001,0.9320000000000002,0.9730000000000001])
decay_data = numpy.array([1.342146870531986,1.405586070225509,1.3439802492549762,1.3567811728250267,1.2666276377825874,1.1686375326985337,1.216119360088685,1.2022841507836042,1.1926979408026064,1.1544395213303447,1.1904416926531907,1.1054720201415882,1.112100683833435,1.0811434035632939,1.1221671794680403,1.0673295063196415,1.0036146509494743,0.9984005680821595,1.0134498134883763,0.9996920772051201,0.929782730581616,0.9646581154122312,0.9290690593684447,0.8907360533169936,0.9121560047238627])
fit_exponential(decay_data, time_data, 0.567)

print

print "Gives results that are way outside my expectations"
time_data = numpy.array([0.0,0.040000000000000036,0.08099999999999996,0.121,0.16199999999999992,0.20199999999999996,0.24300000000000033,0.28300000000000036,0.32399999999999984,0.3650000000000002,0.40500000000000025,0.44599999999999973,0.48599999999999977,0.5270000000000001,0.5670000000000002,0.6079999999999997,0.6479999999999997,0.6890000000000001,0.7290000000000001,0.7700000000000005,0.8100000000000005,0.851,0.8920000000000003,0.9320000000000004,0.9729999999999999,1.013,1.0540000000000003])
decay_data = numpy.array([1.4401611921948776,1.3720688158534153,1.3793465463227048,1.2939909686762128,1.3376345321949346,1.3352710161631154,1.3413634841956348,1.248705138603995,1.2914294791901497,1.2581763134585313,1.246975264018646,1.2006447776495062,1.188232179689515,1.1032789127515186,1.163294324147017,1.1686263160765304,1.1434009568472243,1.0511578409946472,1.0814520440570896,1.1035953824496334,1.0626893599266163,1.0645580326776076,0.994855722989818,0.9959891485338087,0.9394584009825916,0.949504060086646,0.9278639431146273])
fit_exponential(decay_data, time_data, 0.6890000000000001)

這是文本輸出:


Gives reasonable results
guess: [0.4299908658081232, 1.7636684303350971, 0.9121560047238627]
a: 1.10498934435
b: 0.583046565885
c: 0.274503681044

Gives results that are way outside my expectations
guess: [0.5122972490802503, 1.4513788098693758, 0.9278639431146273]
a: 742.824622191
b: 0.000606308344957
c: -741.41398516

最值得注意的是,與第二組的結果,對於一個值是非常高的,與c是同樣低在負的規模,和b為一個非常小的十進制數的值。

這是第一個數據集的圖形,給出了合理的結果。 這是第一個數據集的圖形,給出了合理的結果。

這是第二個數據集的圖形,效果不佳。 這是第二個數據集的圖形,效果不佳。

請注意,盡管線條實際上沒有很好的曲線,但圖形本身可以正確繪制。

我的問題:

  • 我用curve_fit實現的指數衰減算法正確嗎?
  • 我最初的猜測參數是否足夠好?
  • bounds參數是否是此問題的正確解決方案? 如果是這樣,什么是確定下限和上限的好方法?
  • 我在這里錯過了什么嗎?

再次謝謝你!

當您說第二個擬合所提供的結果超出您的期望“並且超出了您的期望”,並且盡管第二個圖形“正確繪制”時,該線並沒有真正“具有良好的曲線擬合”,您在正確的道路上理解了什么是繼續。 我認為您只是迷失了一部分。

第二張圖非常適合看起來確實是線性的曲線。 這可能意味着您實際上沒有足夠的數據變化(很可能低於噪聲水平)來檢測它是指數衰減。

我敢打賭,如果您不僅打印出最佳擬合值,而且還打印出變量的不確定性和相關性,您會發現不確定性很大,並且某些相關性非常接近1。這可能意味着考慮到考慮到不確定性(並且測量始終具有不確定性),結果實際上可能符合您的期望。 這也可能告訴您,您擁有的數據不能很好地支持指數衰減。

您也可以嘗試使用該數據的其他模型(想到“線性”;)並比較擬合優度統計數據,例如卡方和Akaike信息准則。

scipy.curve_fit確實返回協方差矩陣-您在示例中未使用的pcov 不幸的是, scipy.curve_fit不會將這些值轉換為不確定性和相關性值,並且根本不會嘗試返回任何擬合優度統計信息。

為了充分說明對數據的擬合,您不僅需要最佳擬合值,還需要估計可變參數的不確定性。 而且,您需要擬合優度統計信息才能確定擬合是否良好,或者至少確定一個擬合優於另一個擬合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM