同时拟合 python 参数共享
simultaneous fitting python parameter sharing
我有六个数据集,我希望同时拟合所有六个数据集,六个数据集之间有两个参数公共,一个单独拟合。
我计划将一个简单的 ax**2+bx+c 多项式拟合到数据集,其中 a 和 b 在六个数据集之间共享,而偏移量 c 在六个数据集之间不共享。
因此,我在数据集之间拟合了一个共同的斜率,但偏移量可变。
我完全有能力分别对它们进行拟合,但是由于每个数据集之间的斜率相似,因此使用同步拟合可以大大改善偏移量 c 的误差。
我通常适合使用 scipy.optmize.curve_fit。
import numpy as np
from scipy.optimize import curve_fit
def func(x,a,b,c):
return (a*(x**2)+b*x+c)
def fit(x,y,yerr):
popt, pcov = curve_fit(func,x,y,p0=[-0.6,5,-12],sigma=yerr)
chi=np.sum( ((func(x, *popt) - y) / yerr)**2)
redchi=(chi-1)/len(y)
return popt,pcov,redchi,len(y)
我正在处理 6 组:x,xerr,y,yerr
len(x) 和 len(y) 对于每个集合都是不同的。
我知道我必须连接数据集并以这种方式拟合它们。
如果有人可以提供任何建议或帮助,我相信这对我和社区都有好处。
一种可能是改变要拟合的函数,使每个数据集都有自己的 "a" 和 "b" 参数,具有共同的 "c",类似于这个粗略的代码片段:
def func(x,a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6, c):
if x in data_set_1:
return (a1*(x**2)+b1*x+c)
if x in data_set_2:
return (a2*(x**2)+b2*x+c)
if x in data_set_3:
return (a3*(x**2)+b3*x+c)
if x in data_set_4:
return (a4*(x**2)+b4*x+c)
if x in data_set_5:
return (a5*(x**2)+b5*x+c)
if x in data_set_6:
return (a6*(x**2)+b6*x+c)
raise Exception('Data outside fitting range') # just in case
因为我也有类似的拟合问题,所以做了symfit
来应对这种场景。所以我很抱歉无耻地推荐我自己的包裹,但我认为这对你很有帮助。它包装了曲线拟合,但提供了一个符号界面,使事情变得更容易。
您的问题可以这样解决:
from symfit import variables, parameters, Fit
xs = variables('x_1, x_2, x_3, x_4, x_5, x_6')
ys = variables('y_1, y_2, y_3, y_4, y_5, y_6')
a, b = parameters('a, b')
cs = parameters(', '.join('c_{}'.format(i) for i in range(1, 6)))
model_dict = {
y: a * x**2 + b * x + c
for x, y, c in zip(xs, ys, cs)
}
fit = Fit(model_dict, x_1=x1_data, x_2=x2_data, ..., y_1=y1_data, ..., sigma_y_1=y1_err, sigma_y_2=y2_err, ...)
fit_result = fit.execute()
print(fit_result)
查看文档了解更多信息:
http://symfit.readthedocs.io/en/latest/fitting_types.html#global-fitting
p.s。为了对您的参数进行初始猜测,每个 Parameter
对象都带有一个 .value
属性来保存初始猜测。例如,a.value = -0.6
.
编辑:
以前需要一些额外的解决方法,这解释了下面的一些讨论。但是,我现在发布了一个新的 symfit
版本,上面的代码可以按预期运行。
感谢大家的建议,我似乎找到了一种方法,以a,b和c1,c2,c3,c4,c5,c6为参数同时拟合它们,其中a和b是共享的。
下面是我最后使用的代码:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
x=[vt,bt,ut,w1t,m2t,w2t]
y=[vmag,bmag,umag,w1mag,m2mag,w2mag]
xerr=[vterr,uterr,bterr,w1terr,m2terr,w2terr]
yerr=[vmagerr,umagerr,bmagerr,w1magerr,m2magerr,w2magerr]
def poly(x_, a, b, c1, c2, c3, c4, c5, c6):
#all this is just to split x_data into the original parts of x
l= len(x[0])
l1= len(x[1])
l2= len(x[2])
l3= len(x[3])
l4= len(x[4])
l5= len(x[5])
s=l+l1
s1=l2+s
s2=l3+s1
s3=l4+s2
s4=l5+s3
a= np.hstack([
a*x_[:l]**2 + b*x_[:l] +c1,
a*x_[l:(s)]**2 + b*x_[l:(s)] +c2,
a*x_[(s):(s1)]**2 + b*x_[(s):(s1)] +c3,
a*x_[(s1):(s2)]**2 + b*x_[(s1):(s2)] +c4,
a*x_[(s2):(s3)]**2 + b*x_[(s2):(s3)] +c5,
a*x_[(s3):(s4)]**2 + b*x_[(s3):(s4)] +c6
])
print a
return a
x_data = np.hstack([x[0],x[1],x[2],x[3],x[4],x[5]])
y_data = np.hstack([y[0],y[1],y[2],y[3],y[4],y[5]])
(a, b, c1, c2, c3, c4, c5, c6), _ = curve_fit(poly, x_data, y_data)
如果这是糟糕的编码,我们深表歉意!我的方法很粗暴!但是,它确实做得很好!
下面是我的拟合结果。
Fitted results from simultaneous fitting with shared parameters
我有六个数据集,我希望同时拟合所有六个数据集,六个数据集之间有两个参数公共,一个单独拟合。
我计划将一个简单的 ax**2+bx+c 多项式拟合到数据集,其中 a 和 b 在六个数据集之间共享,而偏移量 c 在六个数据集之间不共享。
因此,我在数据集之间拟合了一个共同的斜率,但偏移量可变。
我完全有能力分别对它们进行拟合,但是由于每个数据集之间的斜率相似,因此使用同步拟合可以大大改善偏移量 c 的误差。
我通常适合使用 scipy.optmize.curve_fit。
import numpy as np
from scipy.optimize import curve_fit
def func(x,a,b,c):
return (a*(x**2)+b*x+c)
def fit(x,y,yerr):
popt, pcov = curve_fit(func,x,y,p0=[-0.6,5,-12],sigma=yerr)
chi=np.sum( ((func(x, *popt) - y) / yerr)**2)
redchi=(chi-1)/len(y)
return popt,pcov,redchi,len(y)
我正在处理 6 组:x,xerr,y,yerr len(x) 和 len(y) 对于每个集合都是不同的。
我知道我必须连接数据集并以这种方式拟合它们。
如果有人可以提供任何建议或帮助,我相信这对我和社区都有好处。
一种可能是改变要拟合的函数,使每个数据集都有自己的 "a" 和 "b" 参数,具有共同的 "c",类似于这个粗略的代码片段:
def func(x,a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6, c):
if x in data_set_1:
return (a1*(x**2)+b1*x+c)
if x in data_set_2:
return (a2*(x**2)+b2*x+c)
if x in data_set_3:
return (a3*(x**2)+b3*x+c)
if x in data_set_4:
return (a4*(x**2)+b4*x+c)
if x in data_set_5:
return (a5*(x**2)+b5*x+c)
if x in data_set_6:
return (a6*(x**2)+b6*x+c)
raise Exception('Data outside fitting range') # just in case
因为我也有类似的拟合问题,所以做了symfit
来应对这种场景。所以我很抱歉无耻地推荐我自己的包裹,但我认为这对你很有帮助。它包装了曲线拟合,但提供了一个符号界面,使事情变得更容易。
您的问题可以这样解决:
from symfit import variables, parameters, Fit
xs = variables('x_1, x_2, x_3, x_4, x_5, x_6')
ys = variables('y_1, y_2, y_3, y_4, y_5, y_6')
a, b = parameters('a, b')
cs = parameters(', '.join('c_{}'.format(i) for i in range(1, 6)))
model_dict = {
y: a * x**2 + b * x + c
for x, y, c in zip(xs, ys, cs)
}
fit = Fit(model_dict, x_1=x1_data, x_2=x2_data, ..., y_1=y1_data, ..., sigma_y_1=y1_err, sigma_y_2=y2_err, ...)
fit_result = fit.execute()
print(fit_result)
查看文档了解更多信息: http://symfit.readthedocs.io/en/latest/fitting_types.html#global-fitting
p.s。为了对您的参数进行初始猜测,每个 Parameter
对象都带有一个 .value
属性来保存初始猜测。例如,a.value = -0.6
.
编辑:
以前需要一些额外的解决方法,这解释了下面的一些讨论。但是,我现在发布了一个新的 symfit
版本,上面的代码可以按预期运行。
感谢大家的建议,我似乎找到了一种方法,以a,b和c1,c2,c3,c4,c5,c6为参数同时拟合它们,其中a和b是共享的。
下面是我最后使用的代码:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
x=[vt,bt,ut,w1t,m2t,w2t]
y=[vmag,bmag,umag,w1mag,m2mag,w2mag]
xerr=[vterr,uterr,bterr,w1terr,m2terr,w2terr]
yerr=[vmagerr,umagerr,bmagerr,w1magerr,m2magerr,w2magerr]
def poly(x_, a, b, c1, c2, c3, c4, c5, c6):
#all this is just to split x_data into the original parts of x
l= len(x[0])
l1= len(x[1])
l2= len(x[2])
l3= len(x[3])
l4= len(x[4])
l5= len(x[5])
s=l+l1
s1=l2+s
s2=l3+s1
s3=l4+s2
s4=l5+s3
a= np.hstack([
a*x_[:l]**2 + b*x_[:l] +c1,
a*x_[l:(s)]**2 + b*x_[l:(s)] +c2,
a*x_[(s):(s1)]**2 + b*x_[(s):(s1)] +c3,
a*x_[(s1):(s2)]**2 + b*x_[(s1):(s2)] +c4,
a*x_[(s2):(s3)]**2 + b*x_[(s2):(s3)] +c5,
a*x_[(s3):(s4)]**2 + b*x_[(s3):(s4)] +c6
])
print a
return a
x_data = np.hstack([x[0],x[1],x[2],x[3],x[4],x[5]])
y_data = np.hstack([y[0],y[1],y[2],y[3],y[4],y[5]])
(a, b, c1, c2, c3, c4, c5, c6), _ = curve_fit(poly, x_data, y_data)
如果这是糟糕的编码,我们深表歉意!我的方法很粗暴!但是,它确实做得很好!
下面是我的拟合结果。
Fitted results from simultaneous fitting with shared parameters