Python3、scipy.optimize:将模型拟合到多个数据集
Python3, scipy.optimize: Fit model to multiple datas sets
我有一个模型定义为:
m(x,z) = C1*x^2*sin(z)+C2*x^3*cos(z)
我有多个不同 z (z=1, z=2, z=3) 的数据集,其中它们给我 m(x,z) 作为 x 的函数。
对于所有 z 值,参数 C1 和 C2 必须相同。
所以我必须同时将我的模型拟合到三个数据集,否则对于不同的 z 值,我将具有不同的 C1 和 C2 值。
这可以用 scipy.optimize 来做。
我可以只对一个 z 值执行此操作,但无法弄清楚如何对所有 z 执行此操作。
对于一个 z 我只写这个:
def my_function(x,C1,C1):
z=1
return C1*x**2*np.sin(z)+ C2*x**3*np.cos(z)
data = 'some/path/for/data/z=1'
x= data[:,0]
y= data[:,1]
from lmfit import Model
gmodel = Model(my_function)
result = gmodel.fit(y, x=x, C1=1.1)
print(result.fit_report())
如何为多组数据(即不同的 z 值?)
所以你想要做的是对你的数据进行多维拟合(在你的情况下是二维的);这样,对于整个数据集,您将获得一组最能描述您的数据的 C 参数。我认为最好的方法是使用 scipy.optimize.curve_fit()
.
因此您的代码将如下所示:
import scipy.optimize as optimize
import numpy as np
def my_function(xz, *par):
""" Here xz is a 2D array, so in the form [x, z] using your variables, and *par is an array of arguments (C1, C2) in your case """
x = xz[:,0]
z = xz[:,1]
return par[0] * x**2 * np.sin(z) + par[1] * x**3 * np.cos(z)
# generate fake data. You will presumable have this already
x = np.linspace(0, 10, 100)
z = np.linspace(0, 3, 100)
xx, zz = np.meshgrid(x, z)
xz = np.array([xx.flatten(), zz.flatten()]).T
fakeDataCoefficients = [4, 6.5]
fakeData = my_function(xz, *fakeDataCoefficients) + np.random.uniform(-0.5, 0.5, xx.size)
# Fit the fake data and return the set of coefficients that jointly fit the x and z
# points (and will hopefully be the same as the fakeDataCoefficients
popt, _ = optimize.curve_fit(my_function, xz, fakeData, p0=fakeDataCoefficients)
# Print the results
print(popt)
当我做这个拟合时,我得到了我用来生成函数的精确 fakeDataCoefficients
,所以拟合效果很好。
所以结论是您没有独立进行 3 次拟合,每次都设置 z
的值,而是进行 2D 拟合,它采用 x
和 z
同时求最佳系数。
您的代码不完整并且有一些语法错误。
但我认为您想要构建一个模型,将不同数据集的模型连接起来,然后将连接后的数据拟合到该模型。在 lmfit
(披露:作者和维护者)的上下文中,我经常发现使用 minimize()
和 objective 函数更适合多个数据集,而不是 Model
class。也许从这样的事情开始:
import lmfit
import numpy as np
# define the model function for each dataset
def my_function(x, c1, c2, z=1):
return C1*x**2*np.sin(z)+ C2*x**3*np.cos(z)
# Then write an objective function like this
def f2min(params, x, data2d, zlist):
ndata, npts = data2d.shape
residual = 0.0*data2d[:]
for i in range(ndata):
c1 = params['c1_%d' % (i+1)].value
c2 = params['c2_%d' % (i+1)].value
residual[i,:] = data[i,:] - my_function(x, c1, c2, z=zlist[i])
return residual.flatten()
# now build that `data2d`, `zlist` and build the `Parameters`
data2d = []
zlist = []
x = None
for fname in dataset_names:
d = np.loadtxt(fname) # or however you read / generate data
if x is None: x = d[:, 0]
data2d.append(d[:, 1])
zlist.append(z_for_dataset(fname)) # or however ...
data2d = np.array(data2d) # turn list into nd array
ndata, npts = data2d.shape
params = lmfit.Parameters()
for i in range(ndata):
params.add('c1_%d' % (i+1), value=1.0) # give a better starting value!
params.add('c2_%d' % (i+1), value=1.0) # give a better starting value!
# now you're ready to do the fit and print out the results:
result = lmfit.minimize(f2min, params, args=(x, data2d, zlist))
print(results.fit_report())
该代码实际上是一个草图,还没有经过测试,但希望能为您打下良好的入门基础。
我有一个模型定义为:
m(x,z) = C1*x^2*sin(z)+C2*x^3*cos(z)
我有多个不同 z (z=1, z=2, z=3) 的数据集,其中它们给我 m(x,z) 作为 x 的函数。
对于所有 z 值,参数 C1 和 C2 必须相同。
所以我必须同时将我的模型拟合到三个数据集,否则对于不同的 z 值,我将具有不同的 C1 和 C2 值。
这可以用 scipy.optimize 来做。 我可以只对一个 z 值执行此操作,但无法弄清楚如何对所有 z 执行此操作。
对于一个 z 我只写这个:
def my_function(x,C1,C1):
z=1
return C1*x**2*np.sin(z)+ C2*x**3*np.cos(z)
data = 'some/path/for/data/z=1'
x= data[:,0]
y= data[:,1]
from lmfit import Model
gmodel = Model(my_function)
result = gmodel.fit(y, x=x, C1=1.1)
print(result.fit_report())
如何为多组数据(即不同的 z 值?)
所以你想要做的是对你的数据进行多维拟合(在你的情况下是二维的);这样,对于整个数据集,您将获得一组最能描述您的数据的 C 参数。我认为最好的方法是使用 scipy.optimize.curve_fit()
.
因此您的代码将如下所示:
import scipy.optimize as optimize
import numpy as np
def my_function(xz, *par):
""" Here xz is a 2D array, so in the form [x, z] using your variables, and *par is an array of arguments (C1, C2) in your case """
x = xz[:,0]
z = xz[:,1]
return par[0] * x**2 * np.sin(z) + par[1] * x**3 * np.cos(z)
# generate fake data. You will presumable have this already
x = np.linspace(0, 10, 100)
z = np.linspace(0, 3, 100)
xx, zz = np.meshgrid(x, z)
xz = np.array([xx.flatten(), zz.flatten()]).T
fakeDataCoefficients = [4, 6.5]
fakeData = my_function(xz, *fakeDataCoefficients) + np.random.uniform(-0.5, 0.5, xx.size)
# Fit the fake data and return the set of coefficients that jointly fit the x and z
# points (and will hopefully be the same as the fakeDataCoefficients
popt, _ = optimize.curve_fit(my_function, xz, fakeData, p0=fakeDataCoefficients)
# Print the results
print(popt)
当我做这个拟合时,我得到了我用来生成函数的精确 fakeDataCoefficients
,所以拟合效果很好。
所以结论是您没有独立进行 3 次拟合,每次都设置 z
的值,而是进行 2D 拟合,它采用 x
和 z
同时求最佳系数。
您的代码不完整并且有一些语法错误。
但我认为您想要构建一个模型,将不同数据集的模型连接起来,然后将连接后的数据拟合到该模型。在 lmfit
(披露:作者和维护者)的上下文中,我经常发现使用 minimize()
和 objective 函数更适合多个数据集,而不是 Model
class。也许从这样的事情开始:
import lmfit
import numpy as np
# define the model function for each dataset
def my_function(x, c1, c2, z=1):
return C1*x**2*np.sin(z)+ C2*x**3*np.cos(z)
# Then write an objective function like this
def f2min(params, x, data2d, zlist):
ndata, npts = data2d.shape
residual = 0.0*data2d[:]
for i in range(ndata):
c1 = params['c1_%d' % (i+1)].value
c2 = params['c2_%d' % (i+1)].value
residual[i,:] = data[i,:] - my_function(x, c1, c2, z=zlist[i])
return residual.flatten()
# now build that `data2d`, `zlist` and build the `Parameters`
data2d = []
zlist = []
x = None
for fname in dataset_names:
d = np.loadtxt(fname) # or however you read / generate data
if x is None: x = d[:, 0]
data2d.append(d[:, 1])
zlist.append(z_for_dataset(fname)) # or however ...
data2d = np.array(data2d) # turn list into nd array
ndata, npts = data2d.shape
params = lmfit.Parameters()
for i in range(ndata):
params.add('c1_%d' % (i+1), value=1.0) # give a better starting value!
params.add('c2_%d' % (i+1), value=1.0) # give a better starting value!
# now you're ready to do the fit and print out the results:
result = lmfit.minimize(f2min, params, args=(x, data2d, zlist))
print(results.fit_report())
该代码实际上是一个草图,还没有经过测试,但希望能为您打下良好的入门基础。