Python curve_fit 有多个自变量
Python curve_fit with multiple independent variables
Python 的 curve_fit
计算具有单个自变量的函数的最佳拟合参数,但是有没有办法使用 curve_fit
或其他方法来拟合对于具有多个自变量的函数?例如:
def func(x, y, a, b, c):
return log(a) + b*log(x) + c*log(y)
其中 x 和 y 是自变量,我们希望拟合 a、b 和 c。
是的,有:简单地给curve_fit
一个多维数组xData
。
您可以为自变量传递 curve_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
是由函数 measuredData(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)
结果:
是的。我们可以为 curve_fit 传递多个变量。我写了一段代码:
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,)
在上面的代码中,我生成了 x 形状为 (2,100) 的二维数据集,即有两个具有 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, pcov = curve_fit(model_func,x,y)
popt 是一个包含预测参数的一维 numpy 数组。在我们的例子中有 3 个参数。
优化具有多个输入维度和可变数量参数的函数
此示例说明如何通过增加系数来拟合具有二维输入 (R^2 -> R) 的多项式。设计非常灵活,因此来自 curve_fit 的可调用 f 为任意数量的 non-keyword 个参数定义一次。
最小可重现示例
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()
P.S。这个答案的概念与我在此处的其他答案相同,但代码示例更加清晰。届时我会删除另一个答案。
Python 的 curve_fit
计算具有单个自变量的函数的最佳拟合参数,但是有没有办法使用 curve_fit
或其他方法来拟合对于具有多个自变量的函数?例如:
def func(x, y, a, b, c):
return log(a) + b*log(x) + c*log(y)
其中 x 和 y 是自变量,我们希望拟合 a、b 和 c。
是的,有:简单地给curve_fit
一个多维数组xData
。
您可以为自变量传递 curve_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
是由函数 measuredData(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)
结果:
是的。我们可以为 curve_fit 传递多个变量。我写了一段代码:
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,)
在上面的代码中,我生成了 x 形状为 (2,100) 的二维数据集,即有两个具有 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, pcov = curve_fit(model_func,x,y)
popt 是一个包含预测参数的一维 numpy 数组。在我们的例子中有 3 个参数。
优化具有多个输入维度和可变数量参数的函数
此示例说明如何通过增加系数来拟合具有二维输入 (R^2 -> R) 的多项式。设计非常灵活,因此来自 curve_fit 的可调用 f 为任意数量的 non-keyword 个参数定义一次。
最小可重现示例
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()
P.S。这个答案的概念与我在此处的其他答案相同,但代码示例更加清晰。届时我会删除另一个答案。