需要可选参数的困难python曲线拟合多维任务
我有一组由多个物体的(二维)观测数据组成的数据。观测值可以用一般函数加上每个对象特有的偏移量来描述。我想使用curve_fit同时恢复每个对象的常规函数和偏移(带有相关错误)。我事先不知道数据集将由多少个对象组成,只是每个对象可能有多个观测值 因此,由7个观测值组成的广义数据集可能如下所示:需要可选参数的困难python曲线拟合多维任务,python,curve-fitting,Python,Curve Fitting,我有一组由多个物体的(二维)观测数据组成的数据。观测值可以用一般函数加上每个对象特有的偏移量来描述。我想使用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], y
[[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])和对象偏移量=nx[o1,o2]来拟合函数,然后使用对象标签来决定需要将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的方程,并取均方根来确定g0和g1(这也给了我偏移量['A',0]和偏移量['A',1]分别。我可以对集合中的每个不同对象多次执行此操作,但我不能以这种方式拟合g2参数,因为在对y1或y2函数的任何给定调用中,它都会退化为相应的偏移量。最好显示一个更完整的示例,说明您正在尝试的操作,包括对
scipy.opt的调用imize.curve\u fit
。但是,如果我理解正确,您希望模型函数的参数在fit中不作为变量处理。我相信curve\u fit
无法做到这一点,并且将第一个参数之后的所有参数都作为变量处理
事实上,我认为您的模型函数对于curve\u fit
不起作用,因为您希望g
是一系列值。对于curve\u fit
,第一个参数之后的每个参数都将得到一个浮点值。因此,您可能希望
def func(x, g0, g1, g2, offsets):
y1 = g0 * cos(2*(x - g1)) + offsets['lab', 0] + g2
...
无论如何,我有两个建议来解决曲线拟合的限制:
首先,您可以重载x
。现在,curve\u fit
将在内部应用numpy.asarray()
到您传入的x
,但它只会将其传递给您的模型函数。因此,如果您将x
转换为包含真实x
和lab
的列表,您应该能够在您的模型函数中解包,比如说like
xhack = [x, offsets]
def func(x, g0, g1, g2):
x, offsets = x
....
out = curve_fit(func, xhack, ...)
就我个人而言,我认为这有点难看,但它可能会奏效
第二,可以使用lmfit(),它为曲线拟合提供了更高级别的接口,并修复了曲线拟合
的许多缺点。特别是对于您的问题,lmfit的模型
曲线拟合类更仔细地检查模型函数,以将函数参数转换为拟合参数。具体而言:
具有非数值默认值的关键字参数将不会转换为拟合参数
可以指定多个“自变量”,它们不必是函数的第一个参数
也就是说,你可以写:
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)
或者明确告诉模型
自变量是什么:
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'])
无论哪种方式,offset
都可以是任何复杂的对象,您可以使用此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添加了许多其他便利(我是开发人员之一)用于构建曲线拟合模型和将参数作为高级对象使用,但这可能足以让您开始使用。以下是使用“a”或“B”解码将两个不同的方程与共享参数进行拟合的示例代码。它似乎可以根据您解码实验室类型的需要工作,但我个人以前和现在都没有这样做过虽然它似乎在你的帖子中起作用,但在我看来,函数内部的“文本到浮动”转换似乎很难实现。但它是有效的
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)
谢谢你提出了我的建议!我认为这有点麻烦,但是如果你坚持了<代码> CurvyFult,这是唯一的解决方法。我会仔细考虑你的评论。