[英]How to do curve fitting of a curve family with python/scipy
我有一個解決以下問題:
我希望我能描述我的問題,希望你們能提供幫助,我將非常感激!
問題已編輯(由於誤解 - 2020_04_04)
我現在會嘗試更具體一些,因為我附上了一張圖片,您可以在其中看到“曲線族”的示例,該示例會隨着不同的“Sigma”而變化。 我想用一對常數來描述那些曲線族——C1、C2、C3 和 C4,而不改變它們。 線索是找到一個常數的最佳值,它可以僅以改變 Sigma 和 T 作為變量來描述這個曲線族。 因此,我必須以最小的誤差擬合一堆曲線的參數。 之后,只需更改“Sigma 和 T”,方程就應該涵蓋整個曲線族。
此致!
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
#Equation --> Eps_Cr = (C1*Sigma**C2*x**(C3+1)*e(-C4/T))/(C3+1)
def func(x, C1, C2, C3,C4):
Sigma = 20
T = 1
return (C1*Sigma**C2*x**(C3+1)*np.exp(-C4*1/T))/(C3+1)
#Example Data 1
xdata = [1, 10, 100, 1000, 10000, 100000]
ydata = [0.000382,0.000407,0.000658,0.001169,0.002205,0.004304]
#Example Data 2
xdata1 = [1, 10, 100, 1000, 10000, 100000]
ydata1 = [0.002164,0.002371,0.004441,0.008571,0.016811,0.033261]
#Example Data 3
xdata2 = [1, 10, 100, 1000, 10000, 100000]
ydata2 = [0.001332,0.001457,0.002707,0.005157,0.010007,0.019597]
plt.plot(xdata, ydata, 'b-', label='data')
plt.plot(xdata1, ydata1, 'g-', label='data')
plt.plot(xdata2, ydata2, 'y-', label='data')
popt, pcov = curve_fit(func, xdata, ydata)
plt.plot(xdata, func(xdata, *popt), 'r--',
label='fit: C1=%5.2e, C2=%5.3f, C3=%5.3f,C4=%5.3f' % tuple(popt))
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
從您在“答案”中提供的額外信息來看,您似乎想要適應分層 model。 至少統計學家經常這么稱呼他們。 一些參數在所有數據點之間共享(參數C1
到C4
,一些參數在數據集組內共享( T
和Sigma
)。所有這些參數都需要從數據中估計。
這通常通過為所有數據構建更大的 model 來解決,並在 model 中構建一個 select 來使用分組參數。 如果一個數據點屬於數據組1
,我們選擇Sigma1
和T1
等等......
由於您已經在使用curve_fit
,因此我制作了一個可以完成這項工作的代碼版本。 由於我不是scipy
方面的專家,因此代碼風格有點要求,但我認為您至少會理解該方法。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def func(x_and_grp, C1, C2, C3, C4, Sigma0, Sigma1, Sigma2, T0, T1, T2):
# We estimate one sigma and one T per group of data points
x = x_and_grp[:,0]
grp_id = x_and_grp[:,1]
# here we select the appropriate T and Sigma for each data point based on their group id
T = np.array([[T0, T1, T2][int(gid)] for gid in grp_id])
Sigma = np.array([[Sigma0, Sigma1, Sigma2][int(gid)] for gid in grp_id])
return (C1*Sigma**C2*x**(C3+1)*np.exp(-C4*1/T))/(C3+1)
#Example Data in 3 groups
xdata0 = [1, 10, 100, 1000, 10000, 100000]
ydata0 = [0.000382,0.000407,0.000658,0.001169,0.002205,0.004304]
xdata1 = [1, 10, 100, 1000, 10000, 100000]
ydata1 = [0.002164,0.002371,0.004441,0.008571,0.016811,0.033261]
xdata2 = [1, 10, 100, 1000, 10000, 100000]
ydata2 = [0.001332,0.001457,0.002707,0.005157,0.010007,0.019597]
# merge all the data and add the group id to the x-data vectors
y_all = np.concatenate([ydata0, ydata1, ydata2])
x_and_grp_all = np.zeros(shape=(3 * 6, 2))
x_and_grp_all[:, 0] = np.concatenate([xdata0, xdata1, xdata2])
x_and_grp_all[0:6, 1] = 0
x_and_grp_all[6:12, 1] = 1
x_and_grp_all[12:18, 1] = 2
# fit a model to all the data together
popt, pcov = curve_fit(func, x_and_grp_all, y_all)
xspace = np.logspace(1,5)
plt.plot(xdata0, ydata0, 'b-', label='data')
plt.plot(xdata1, ydata1, 'g-', label='data')
plt.plot(xdata2, ydata2, 'y-', label='data')
for gid,color in zip([0,1,2],['r','k','purple']):
T = popt[4+gid]
Sigma = popt[7+gid]
x_and_grp = np.column_stack([xspace,np.ones_like(xspace)*gid])
plt.plot(xspace,
func(x_and_grp, *popt),
linestyle='dashed', color=color,
label='fit: T=%5.2e, Sigma=%5.3f' % (T,Sigma))
plt.xlabel('X')
plt.ylabel('Y')
plt.title('fit: C1=%5.2e, C2=%5.3f, C3=%5.3f,C4=%5.3f' % tuple(popt[0:4]))
plt.legend()
plt.show()
最后,我想補充一點,如果您有很多不同的組, curve_fit
不太適合這項任務。 考慮一些其他可能相關的庫。 Statmodels 是可能的。 一種替代方法是使用scipy.optimize.minimze
,因為它為您提供了更大的靈活性。 您需要手動進行置信區間估計......
我還想補充一點,如果您知道每組數據的T
和Sigma
,則上述方法過於復雜。 在這種情況下,我們將Sigma
和T
的相關值添加到 x 向量,而不是組 id。
根據您的查詢,我可以理解您需要分別為三個不同的數據集擬合一個方程。 因此,我通過保持 sigma 和 T 相同來更新您的代碼。 請看一下,讓我進一步了解。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
#Equation --> Eps_Cr = (C1*Sigma**C2*x**(C3+1)*e(-C4/T))/(C3+1)
def func(x, C1, C2, C3,C4):
Sigma = 20
T = 1
return (C1*Sigma**C2*x**(C3+1)*np.exp(-C4*1/T))/(C3+1)
#Example Data 1
xdata = [1, 10, 100, 1000, 10000, 100000]
ydata = [0.000382,0.000407,0.000658,0.001169,0.002205,0.004304]
#Example Data 2
xdata1 = [1, 10, 100, 1000, 10000, 100000]
ydata1 = [0.002164,0.002371,0.004441,0.008571,0.016811,0.033261]
#Example Data 3
xdata2 = [1, 10, 100, 1000, 10000, 100000]
ydata2 = [0.001332,0.001457,0.002707,0.005157,0.010007,0.019597]
plt.plot(xdata, ydata, 'b-', label='data 1')
plt.plot(xdata1, ydata1, 'g-', label='data 2')
plt.plot(xdata2, ydata2, 'y-', label='data 3')
popt, pcov = curve_fit(func, xdata, ydata)
popt1, pcov1 = curve_fit(func, xdata1, ydata1)
popt2, pcov2 = curve_fit(func, xdata2, ydata2)
plt.plot(xdata, func(xdata, *popt), 'r.',
label='fit for Data 1: C1=%5.2e, C2=%5.3f, C3=%5.3f,C4=%5.3f' % tuple(popt))
plt.plot(xdata1, func(xdata1, *popt1), 'r+',
label='fit for Data 2: C1=%5.2e, C2=%5.3f, C3=%5.3f,C4=%5.3f' % tuple(popt1))
plt.plot(xdata2, func(xdata2, *popt2), 'r--',
label='fit for Data 3 : C1=%5.2e, C2=%5.3f, C3=%5.3f,C4=%5.3f' % tuple(popt2))
plt.xlabel('X')
plt.ylabel('Y')
plt.legend(loc='upper left',prop={'size': 8})
plt.show()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.