[英]Gaussian fit for Python
我正在嘗試為我的數據擬合高斯(這已經是一個粗略的高斯)。 我已經聽取了這里的建議並嘗試了curve_fit
和leastsq
但我認為我缺少一些更基本的東西(因為我不知道如何使用該命令)。 這是我到目前為止的腳本
import pylab as plb
import matplotlib.pyplot as plt
# Read in data -- first 2 rows are header in this example.
data = plb.loadtxt('part 2.csv', skiprows=2, delimiter=',')
x = data[:,2]
y = data[:,3]
mean = sum(x*y)
sigma = sum(y*(x - mean)**2)
def gauss_function(x, a, x0, sigma):
return a*np.exp(-(x-x0)**2/(2*sigma**2))
popt, pcov = curve_fit(gauss_function, x, y, p0 = [1, mean, sigma])
plt.plot(x, gauss_function(x, *popt), label='fit')
# plot data
plt.plot(x, y,'b')
# Add some axis labels
plt.legend()
plt.title('Fig. 3 - Fit for Time Constant')
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()
我從中得到的是一個高斯形狀,這是我的原始數據,以及一條水平直線。
另外,我想使用點繪制我的圖形,而不是將它們連接起來。 任何輸入表示贊賞!
這是更正的代碼:
import pylab as plb
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy import asarray as ar,exp
x = ar(range(10))
y = ar([0,1,2,3,4,5,4,3,2,1])
n = len(x) #the number of data
mean = sum(x*y)/n #note this correction
sigma = sum(y*(x-mean)**2)/n #note this correction
def gaus(x,a,x0,sigma):
return a*exp(-(x-x0)**2/(2*sigma**2))
popt,pcov = curve_fit(gaus,x,y,p0=[1,mean,sigma])
plt.plot(x,y,'b+:',label='data')
plt.plot(x,gaus(x,*popt),'ro:',label='fit')
plt.legend()
plt.title('Fig. 3 - Fit for Time Constant')
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()
結果:
您需要良好的起始值,以便curve_fit
函數收斂於“良好”值。 我真的不能說為什么你的擬合沒有收斂(即使你的平均值的定義很奇怪 - 請在下面查看)但我會給你一個適用於像你這樣的非標准化高斯函數的策略。
估計參數應該接近最終值(使用加權算術平均值- 除以所有值的總和):
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
x = np.arange(10)
y = np.array([0, 1, 2, 3, 4, 5, 4, 3, 2, 1])
# weighted arithmetic mean (corrected - check the section below)
mean = sum(x * y) / sum(y)
sigma = np.sqrt(sum(y * (x - mean)**2) / sum(y))
def Gauss(x, a, x0, sigma):
return a * np.exp(-(x - x0)**2 / (2 * sigma**2))
popt,pcov = curve_fit(Gauss, x, y, p0=[max(y), mean, sigma])
plt.plot(x, y, 'b+:', label='data')
plt.plot(x, Gauss(x, *popt), 'r-', label='fit')
plt.legend()
plt.title('Fig. 3 - Fit for Time Constant')
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()
我個人更喜歡使用 numpy。
由於審閱者不喜歡我對 #Developer's code 的編輯,我將解釋在什么情況下我會建議改進代碼。 開發人員的平均值不符合平均值的正常定義之一。
您的定義返回:
>>> sum(x * y)
125
開發者定義返回:
>>> sum(x * y) / len(x)
12.5 #for Python 3.x
加權算術平均值:
>>> sum(x * y) / sum(y)
5.0
同樣,您可以比較標准偏差 ( sigma
) 的定義。 與得到的擬合圖進行比較:
在 Python 2.x 中,您還應該使用新的除法來避免出現奇怪的結果或顯式轉換除法之前的數字:
from __future__ import division
或例如
sum(x * y) * 1. / sum(y)
你得到一條水平直線,因為它沒有收斂。
如果在示例中將擬合的第一個參數 (p0) 設為 max(y), 5 而不是 1,則可以獲得更好的收斂性。
在花了幾個小時試圖找到我的錯誤之后,問題是你的公式:
sigma = sum(y*(x-mean)**2)/n
這個前面的公式是錯誤的,正確的公式是這個的平方根!;
sqrt(sum(y*(x-mean)**2)/n)
希望這有幫助
還有另一種執行擬合的方法,即使用 'lmfit' 包。 它基本上使用 cuve_fit 但在擬合方面要好得多,並且還提供復雜的擬合。 下面的鏈接中給出了詳細的分步說明。 http://cars9.uchicago.edu/software/python/lmfit/model.html#model.best_fit
sigma = sum(y*(x - mean)**2)
應該是
sigma = np.sqrt(sum(y*(x - mean)**2))
實際上,您無需進行初步猜測。 簡單地做
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy import asarray as ar,exp
x = ar(range(10))
y = ar([0,1,2,3,4,5,4,3,2,1])
n = len(x) #the number of data
mean = sum(x*y)/n #note this correction
sigma = sum(y*(x-mean)**2)/n #note this correction
def gaus(x,a,x0,sigma):
return a*exp(-(x-x0)**2/(2*sigma**2))
popt,pcov = curve_fit(gaus,x,y)
#popt,pcov = curve_fit(gaus,x,y,p0=[1,mean,sigma])
plt.plot(x,y,'b+:',label='data')
plt.plot(x,gaus(x,*popt),'ro:',label='fit')
plt.legend()
plt.title('Fig. 3 - Fit for Time Constant')
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
plt.show()
工作正常。 這更簡單,因為進行猜測並非易事。 我有更復雜的數據,並沒有設法進行正確的第一次猜測,但只需刪除第一次猜測就可以正常工作:)
PS:使用 numpy.exp() 更好,說 scipy 的警告
這個問題也在這里得到了回答: How can I fit a gaussian curve in python?
在 MSeifert 的回答中,還提到了使用 astropy 包的簡單高斯建模。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.