多自变量Python曲线拟合

多自变量Python曲线拟合,python,scipy,curve-fitting,Python,Scipy,Curve Fitting,Python用一个独立变量计算函数的最佳拟合参数,但是有没有办法用curve\u fit或其他方法来拟合一个具有多个独立变量的函数?例如: def func(x, y, a, b, c): return log(a) + b*log(x) + c*log(y) 其中x和y是自变量,我们希望对a、b和c进行拟合。是的,有:只需为curve\u-fit扩展数据提供多维数组xData您可以为自变量传递curve\u-fit多维数组,但是您的func必须接受相同的内容。例如,调用此数组X,并将

Python用一个独立变量计算函数的最佳拟合参数,但是有没有办法用
curve\u fit
或其他方法来拟合一个具有多个独立变量的函数?例如:

def func(x, y, a, b, c):
    return log(a) + b*log(x) + c*log(y)

其中x和y是自变量,我们希望对a、b和c进行拟合。

是的,有:只需为
curve\u-fit
扩展数据提供多维数组
xData

您可以为自变量传递
curve\u-fit
多维数组,但是您的
func
必须接受相同的内容。例如,调用此数组
X
,并将其解包到
X
y
,以清晰起见:

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., 101)
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)
适合:

(array([ 9.99933937,  3.99710083,  6.00875164]), array([[  1.75295644e-03,   9.34724308e-05,  -2.90150983e-04],
   [  9.34724308e-05,   5.09079478e-06,  -1.53939905e-05],
   [ -2.90150983e-04,  -1.53939905e-05,   4.84935731e-05]]))

拟合到未知数量的参数

在本例中,我们尝试重现一些测量数据
measData
。 在本例中,
measData
由函数
measuredata(x,a=.2,b=-2,c=-8,d=.1)生成。我的实践是,我们可能在某种程度上测量了
measData
,所以我们不知道它是如何用数学描述的。因此适合

我们通过多项式拟合,多项式由函数
polynomFit(inp,*args)
描述。当我们想要尝试不同阶的多项式时,输入参数的数量必须灵活。 自变量(在您的例子中是x和y)被编码在
inp
的'columns'/第二维度中

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def measuredData(inp, a=.2, b=-2, c=-.8, d=.1):
    x=inp[:,0]
    y=inp[:,1]
    return a+b*x+c*x**2+d*x**3 +y

def polynomFit(inp, *args):
    x=inp[:,0]
    y=inp[:,1]
    res=0
    for order in range(len(args)):
        print(14,order,args[order],x)
        res+=args[order] * x**order
    return res +y


inpData=np.linspace(0,10,20).reshape(-1,2)
inpDataStr=['({:.1f},{:.1f})'.format(a,b) for a,b in inpData]
measData=measuredData(inpData)
fig, ax = plt.subplots()
ax.plot(np.arange(inpData.shape[0]), measData, label='measuered', marker='o', linestyle='none' )

for order in range(5):
    print(27,inpData)
    print(28,measData)
    popt, pcov = curve_fit(polynomFit, xdata=inpData, ydata=measData, p0=[0]*(order+1) )
    fitData=polynomFit(inpData,*popt)
    ax.plot(np.arange(inpData.shape[0]), fitData, label='polyn. fit, order '+str(order), linestyle='--' )
    ax.legend( loc='upper left', bbox_to_anchor=(1.05, 1))
    print(order, popt)

ax.set_xticklabels(inpDataStr, rotation=90)
结果:


是的。我们可以为曲线拟合传递多个变量。我写了一段代码:

import numpy as np
x = np.random.randn(2,100)
w = np.array([1.5,0.5]).reshape(1,2)
esp = np.random.randn(1,100)
y = np.dot(w,x)+esp
y = y.reshape(100,)
在上面的代码中,我生成了一个形状为(2100)的2D数据集,即有两个变量和100个数据点。我已经拟合了因变量y和自变量x以及一些噪声

def model_func(x,w1,w2,b):
  w = np.array([w1,w2]).reshape(1,2)
  b = np.array([b]).reshape(1,1)
  y_p = np.dot(w,x)+b
  return y_p.reshape(100,)
我们定义了一个模型函数,用于建立y和x之间的关系。
注意:模型函数或预测y的输出形状应为(x的长度,)

popt是包含预测参数的一维numpy数组。在我们的例子中有3个参数。

优化具有多个输入维度和可变参数数的函数 这个例子展示了如何通过增加系数的数量来拟合具有二维输入(R^2->R)的多项式。该设计非常灵活,因此可以为任意数量的非关键字参数定义一次可调用的f from

最小可重复示例

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def poly2d(xy, *coefficients):
    x = xy[:, 0]
    y = xy[:, 1]
    proj = x + y
    res = 0
    for order, coef in enumerate(coefficients):
        res += coef * proj ** order
    return res

nx = 31
ny = 21

range_x = [-1.5, 1.5]
range_y = [-1, 1]
target_coefficients = (3, 0, -19, 7)

xs = np.linspace(*range_x, nx)
ys = np.linspace(*range_y, ny)
im_x, im_y = np.meshgrid(xs, ys)
xdata = np.c_[im_x.flatten(), im_y.flatten()]
im_target = poly2d(xdata, *target_coefficients).reshape(ny, nx)

fig, axs = plt.subplots(2, 3, figsize=(29.7, 21))
axs = axs.flatten()

ax = axs[0]
ax.set_title('Unknown polynomial P(x+y)\n[secret coefficients: ' + str(target_coefficients) + ']')
sm = ax.imshow(
    im_target,
    cmap = plt.get_cmap('coolwarm'),
    origin='lower'
    )
fig.colorbar(sm, ax=ax)

for order in range(5):
    ydata=im_target.flatten()
    popt, pcov = curve_fit(poly2d, xdata=xdata, ydata=ydata, p0=[0]*(order+1) )

    im_fit = poly2d(xdata, *popt).reshape(ny, nx)

    ax = axs[1+order]
    title = 'Fit O({:d}):'.format(order)
    for o, p in enumerate(popt):
        if o%2 == 0:
            title += '\n'
        if o == 0:
            title += ' {:=-{w}.1f} (x+y)^{:d}'.format(p, o, w=int(np.log10(max(abs(p), 1))) + 5)
        else:
            title += ' {:=+{w}.1f} (x+y)^{:d}'.format(p, o, w=int(np.log10(max(abs(p), 1))) + 5)
    title += '\nrms: {:.1f}'.format( np.mean((im_fit-im_target)**2)**.5 )
    ax.set_title(title)
    sm = ax.imshow(
        im_fit,
        cmap = plt.get_cmap('coolwarm'),
        origin='lower'
        )
    fig.colorbar(sm, ax=ax)

for ax in axs.flatten():
    ax.set_xlabel('x')
    ax.set_ylabel('y')

plt.show()

另外,这个答案的概念与我这里的另一个答案相同,但代码示例更清楚。在给定的时间,我将删除另一个答案。

我一直试图将x和y组合成一个数组
z=[x,y],这样
x=z[0]和
y=z[1]
。但是
curve\u fit
似乎不喜欢这样,并且给了我一个错误:
TypeError:不支持的操作数类型/:“list”和“float”
如果x和y的大小不同,是否有办法修改解决方案以使用curve fit。例如,x=linspace(0.1,1.1101)和y=np.array([1.0,2.0])?我不确定我是否理解了:
func
表示一个二元函数(取两个独立变量),因此对于拟合,它应该定义为对任何提供的输入值x_I和y_I给出一个结果f(x_I,y_I)。如果
x
y
没有相同的大小,那么您将尝试对其进行评估,例如在某个
x
处,但是
y
未定义,这肯定无法完成。我只想分享我对@ScottG相同问题的解决方案。假设x方向有20个样本,y方向有30个样本,每个交点的数据(20x30=总共600个样本)。我使用
x,y=np.mesgrid(x,y)
然后
np.stack((x,y),axis=2)。重塑(-1,2)
得到一个
(600,2)
数组,它将是
xdata
,包含所有600个x和y组合。然后我将600个样本中的数据展平到一个1d
(600,)
数组中,该数组将是
ydata
,而不是2d
(20,30)
数组。然后您可以使用
x,y=np.hsplit(x,2)
在func中解压数据。(
X
xdata
popt, pcov = curve_fit(model_func,x,y)
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def poly2d(xy, *coefficients):
    x = xy[:, 0]
    y = xy[:, 1]
    proj = x + y
    res = 0
    for order, coef in enumerate(coefficients):
        res += coef * proj ** order
    return res

nx = 31
ny = 21

range_x = [-1.5, 1.5]
range_y = [-1, 1]
target_coefficients = (3, 0, -19, 7)

xs = np.linspace(*range_x, nx)
ys = np.linspace(*range_y, ny)
im_x, im_y = np.meshgrid(xs, ys)
xdata = np.c_[im_x.flatten(), im_y.flatten()]
im_target = poly2d(xdata, *target_coefficients).reshape(ny, nx)

fig, axs = plt.subplots(2, 3, figsize=(29.7, 21))
axs = axs.flatten()

ax = axs[0]
ax.set_title('Unknown polynomial P(x+y)\n[secret coefficients: ' + str(target_coefficients) + ']')
sm = ax.imshow(
    im_target,
    cmap = plt.get_cmap('coolwarm'),
    origin='lower'
    )
fig.colorbar(sm, ax=ax)

for order in range(5):
    ydata=im_target.flatten()
    popt, pcov = curve_fit(poly2d, xdata=xdata, ydata=ydata, p0=[0]*(order+1) )

    im_fit = poly2d(xdata, *popt).reshape(ny, nx)

    ax = axs[1+order]
    title = 'Fit O({:d}):'.format(order)
    for o, p in enumerate(popt):
        if o%2 == 0:
            title += '\n'
        if o == 0:
            title += ' {:=-{w}.1f} (x+y)^{:d}'.format(p, o, w=int(np.log10(max(abs(p), 1))) + 5)
        else:
            title += ' {:=+{w}.1f} (x+y)^{:d}'.format(p, o, w=int(np.log10(max(abs(p), 1))) + 5)
    title += '\nrms: {:.1f}'.format( np.mean((im_fit-im_target)**2)**.5 )
    ax.set_title(title)
    sm = ax.imshow(
        im_fit,
        cmap = plt.get_cmap('coolwarm'),
        origin='lower'
        )
    fig.colorbar(sm, ax=ax)

for ax in axs.flatten():
    ax.set_xlabel('x')
    ax.set_ylabel('y')

plt.show()