我有一组数据由多个对象的(二维)观察组成。观察结果可以通过一般函数加上每个对象唯一的偏移量来描述。我想使用curve_fit同时恢复每个对象的常规函数和偏移量(带有相关的错误)。我事先并不知道数据集将由多少个对象构成,只是每个对象可能有多个观察结果。
因此,7个观测值的广义数据集可能如下所示:
[[x[0], y1[0], y2[0], lab='A'],
[x[1], y1[1], y2[1], lab='B'],
[x[2], y1[2], y2[2], lab='A'],
[x[3], y1[3], y2[3], lab='A'],
[x[4], y1[4], y2[4], lab='B'],
[x[5], y1[5], y2[5], lab='C'],
[x[6], y1[6], y2[6], lab='A']]
我可以通过传递一般函数的参数(比如g = [g0,g1,g2])和对象偏移offsets = nx [o1,o2]到fit_func,然后使用对象标签来决定任务需要将n个偏移中的哪一个添加到常规函数中,除了我无法弄清楚如何传递标签。
def fit_func(x, g, offsets, lab):
y1 = g[0] * cos(2*(x - g[1])) + offsets['lab',0] + g[2]
y2 = g[0] * sin(2*(x - g[1])) + offsets['lab',1] + g[2]
return [y1, y2]
问题是实验室不适合浮动,所以我无法弄清楚如何通过它。从阅读其他一些线程我相信我将需要一个包装器函数,但我无法弄清楚它应该采用什么形式,然后如何以我可以指定sigma和p0的方式调用它。
有人能指出我正确的方向吗?
编辑:我设法生成了一个我认为可行的功能。它使用全局参数调用来选择函数调用中的选项。因此,例如,我交错了y1和y2数组,并让函数在每次运行时使用全局getEven()和setEven(bool)调用调用第二个等式。但是curve_fit真的不喜欢那样。拟合值是荒谬的。
此刻我分别拟合y1的等式和y2的等式,并取rms来确定g0和g1(这也给我偏移['A',0]和偏移['A',1]我可以对集合中的每个不同对象多次执行此操作,但是我不能以这种方式拟合g2参数,因为在任何给定的y1或y2函数调用中,它都会使用相应的偏移量退化。
答案 0 :(得分:1)
这是一个示例代码,它使用' A'来匹配具有共享参数的两个不同方程。或者' B'解码。它看起来像你需要解码实验室类型一样工作,但我个人从来没有这样做过,虽然它似乎按照你的帖子运行" text-to-float"函数内部的转换对我来说似乎很笨拙。但它确实有效。
import numpy
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# single array with all "X" data to pass around
num = numpy.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0])
ids = numpy.array(['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'])
xdata = numpy.array([num, ids]) # combine data, numpy auto-converts to 'text' type
# ydata is numeric single array
ydata = [9.0,8.0,7.0,6.0,4.0,3.0,2.0,1.0]
def fitFunction(data, commonParameter, pA, pB):
numericDataAsText = data[0]
textData = data[1]
returnArray = []
for i in range(len(textData)):
x = float(numericDataAsText[i])
if textData[i] == 'A':
val = commonParameter + x * pA
elif textData[i] == 'B':
val = commonParameter + x * pB
else:
raise(Exception('Error: must use A or B'))
returnArray.append(val)
return returnArray
initialParameters = [1.0, 1.0, 1.0]
# curve fit the equations individually to their respective data
params, pcov = curve_fit(fitFunction, xdata, ydata, initialParameters)
# values for display of fitted function
commonParameter, pA, pB = params
# for plotting the fitting results
y_fit = fitFunction(xdata, commonParameter, pA, pB)
plt.plot(xdata[0], ydata, 'D') # plot the raw data as a scatterplot
plt.plot(xdata[0][:4], y_fit[:4])
plt.plot(xdata[0][4:], y_fit[4:])
plt.show()
print('fittedparameters:', params)
答案 1 :(得分:0)
显示您正在尝试的内容的更完整示例会很有帮助,包括对scipy.optimize.curve_fit
的调用。但是,如果我正确理解了这个问题,你希望你的模型函数有一个参数,不被视为拟合中的一个变量。我认为curve_fit
不能这样做,并将第一个之后的所有参数视为变量。
事实上,我认为您的模型函数不适用于curve_fit
,因为您希望g
是一系列值。对于curve_fit
,第一个之后的每个参数都将获得一个浮点值。所以你可能想要像
def func(x, g0, g1, g2, offsets):
y1 = g0 * cos(2*(x - g1)) + offsets['lab', 0] + g2
...
无论如何,我有两个建议可以解决curve_fit
的这个限制:
首先,您可以重载x
。现在,curve_fit
会在内部将numpy.asarray()
应用于您传入的x
,但它会将其传递给您的模型函数。因此,如果您将x
转换为包含真实x
和lab
的列表,您应该可以在模型函数中解压缩,例如
xhack = [x, offsets]
def func(x, g0, g1, g2):
x, offsets = x
....
out = curve_fit(func, xhack, ...)
就个人而言,我认为这有点难看,但它可能有用。
其次,您可以使用lmfit(https://lmfit.github.io/lmfit-py/),它为曲线拟合提供了更高级别的界面,并修复了curve_fit
的许多缺点。特别是对于你的问题,lmfit用于曲线拟合的Model
类更仔细地检查模型函数,以将函数参数转换为拟合参数。具体做法是:
非数字默认值的关键字参数不会转换为适合参数。
您可以指定多个“自变量”,它们不必是该函数的第一个参数。
也就是说,你可以写:
from lmfit import Model
def func(x, g0, g1, g2, offsets=None):
y1 = g0 * cos(2*(x - g1)) + offsets['lab', 0] + g2
mymodel = Model(func)
或明确告诉Model
自变量是什么:
from lmfit import Model
def func(x, g0, g1, g2, offsets):
y1 = g0 * cos(2*(x - g1)) + offsets['lab', 0] + g2
mymodel = Model(func, independent_vars=['x', 'offsets'])
无论哪种方式,offsets
都可以是任何复杂的对象,您可以使用此mymodel
进行曲线拟合:
# create parameter objects for this model, with initial values:
params = mymodel.make_params(g0=0, g1=0.5, g2=2.0)
# run the fit
result = mymodel.fit(ydata, params, x=x, offsets=offsets)
我们为lmfit(我是其中一个开发人员)添加了许多其他便利,用于构建曲线拟合模型并将参数作为高级对象使用,但这可能足以让您入门。