我试图将一些数据拟合到具有两个独立变量的非线性模型,但是两个自变量的向量长度是xdat
小于ydat
。
这与此问题密切相关:Python curve_fit with multiple independent variables,但xdat
和ydat
大小不同的要求似乎打破了局面。
让我们采用xnx的示例解决方案,但改变其中一个数组的长度:
import numpy as np
from scipy.optimize import curve_fit
def func(X, a, b, c):
x,y = X
return np.log(a) + b*np.log(x) + c*np.log(y)
# some artificially noisy data to fit
x = np.linspace(0.1,1.1,101)
y = np.linspace(1.,2., 90) #I have changed the length of one of these arrays
a, b, c = 10., 4., 6.
z = func((x,y), a, b, c) * 1 + np.random.random(101) / 100
# initial guesses for a,b,c:
p0 = 8., 2., 7.
print curve_fit(func, (x,y), z, p0)
如果你这样做,那么你最终会得到错误:
ValueError:操作数无法与形状一起广播 (101,)(90,)
有没有办法强制曲线拟合来获取不同长度的数组?
答案 0 :(得分:4)
有两个问题,第一个是,你的函数必须返回一个1d数组才能被curve_fit
使用。您可以使用numpy中的ravel()
来实现这一目标。要恢复原始形状,可以使用reshape(xdim, ydim)
。
另一件事是你的自变量的维度。你必须生成一个完整的网格,而不仅仅是两个向量。您可以使用meshgrid()
执行此操作。
import numpy as np
from scipy.optimize import curve_fit
def func(X, a, b, c):
x,y = X
result = np.log(a) + b*np.log(x) + c*np.log(y)
return result.ravel()
xdim = 101
ydim = 90
x = np.linspace(0.1,1.1,xdim)
y = np.linspace(1.,2., ydim)
X=np.meshgrid(x,y)
a, b, c = 10., 4., 6.
z = func(X, a, b, c) * 1 + np.random.random(xdim*ydim) / 100
p0 = 8., 2., 7.
print(curve_fit(func, X, z, p0))
这导致a = 10.05005705,b = 4.00004791,c = 6.00011176。
答案 1 :(得分:1)
您可能会发现lmfit(https://lmfit.github.io/lmfit-py/)对此有帮助。它对curve_fit
的曲线拟合有不同的看法,但在许多改进中,它确实支持多个自变量,并且它们不需要位于第一个参数位置(这是默认值但可以更改)或与数据长度相同的数组。
对于一般的最小化问题,没有"自变量"的概念。存在可变参数,并且根据这些参数计算残差。可能使用额外信息(如数据(!),或不确定性,或独立变量或可能用于计算残差的可选开关这一事实对于最小化例程完全不重要。因此,多个"独立变量",其中一些可能是与数据长度相同的数组,或者可能是布尔,字典或其他自定义对象,不应该是概念性问题,应该被允许。
Lmfit确实允许所有这些。默认情况下,具有数字默认值的位置或关键字参数的函数参数被假定为参数,除了那些显式调用的自变量。但您可以覆盖这些默认值。