同时使用两个不同的模型函数拟合两组数据,以提供唯一的最佳参数

时间:2018-08-18 07:01:41

标签: optimization scipy curve-fitting

我是python的新手。我使用curve_fit中的scipy.optimize,试图同时使用两个具有相同模型参数的参数来优化具有两个不同模型函数(每个用于一组数据)的两组数据。

以下是拟合代码的草图:

def f(x,a,b,c,d,e): 
   return some function

def g(x,a,b,c,d,e): 
   return some other function

a=1
b=2
c=3
d=4
e=5

guesspar=(a,b,c,d,e)
optimalparf, covf=opti.curve_fit(f,x,ydata1,guesspar,some sigma)

print optimalparf


guesspar=(a,b,c,d,e)
optimalparg, covg=opti.curve_fit(g,x,ydata2,guesspar,some sigma)

print optimalparg

其中guesspar是参数的初始值,optimumparf和optimumparg是我要搜索的最优值,ydata1和ydata2是两组数据,covf和covg是协方差矩阵。

现在,我的问题如下:我确实为guesspar得到了两组不同的最优值,这显然是错误的,因为对于整个图,即对于两个模型函数,最优值应该相同。 (此外,在我感兴趣的上下文中,最优值的集合之一是胡说八道)。

我知道,我在这里编写的代码非常容易引起误解。我想知道一个提示,即如何用两个不同的函数同时拟合两组数据来拟合两组数据,从而导致一组唯一的最佳参数。

PS: 这里是原始代码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import ion 
import time
import random as rd 
import scipy.optimize as opti 
import sys
from numpy import *

n0=1.5 

data =np.genfromtxt('some data') 
data=1000*data

pos=[]
for j in range(len(data)): 
pos.append(np.arcsin(np.sin(np.deg2rad(data[j,0]/1000))/1.5))

m1=[]
for j in range(len(data)): 
m1.append(data[j,1]) 

m1Sig=[]
for j in range(len(data)): 
m1Sig.append(data[j,2]) 

p1=[]
for j in range(len(data)): 
p1.append(data[j,3]) 

p1Sig=[]
for j in range(len(data)): 
p1Sig.append(data[j,4]) 

zero=[]
for j in range(len(data)): 
zero.append(data[j,5]) 

zeroSig=[]
for j in range(len(data)): 
zeroSig.append(data[j,6]) 

#define theta plot-range
thetaMin=-0.5 #[rad]
thetaMax=0.5 
thetaStep=1./635.
theta=np.arange(thetaMin,thetaMax,thetaStep) 
#define r plot-range
rMin=0.02 
rMax=0.09

comboY = np.append(m1, p1)

comboX = np.append(pos, pos)
comboTheta = np.append(theta, theta)

def rM1(theta,lam,d0,deltan,per,y0): 
return y0+((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.*np.sin(np.sqrt(((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.+((np.pi*d0*(-np.arcsin(lam/(2*per*n0))-theta))/per)**2.))**2./(((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.+((np.pi*d0*(-np.arcsin(lam/(2*per*n0))-theta))/per)**2.) 


def rP1(theta,lam,d0,deltan,per,y0): 
return y0+((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.*np.sin(np.sqrt(((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.+((np.pi*d0*(np.arcsin(lam/(2*per*n0))-theta))/per)**2.))**2./(((np.pi*deltan*d0)/(lam*np.cos(theta)))**2.+((np.pi*d0*(np.arcsin(lam/(2*per*n0))-theta))/per)**2.)


def combinedFunction(comboData,lam,d0,deltan,per,y0):

result1 = rM1(theta,lam,d0,deltan,per,y0)
result2 = rP1(theta,lam,d0,deltan,per,y0)

return np.append(result1, result2)

lam1=0.633
d01=100.
deltan1=0.0005
per1=1. 
y01=0.02

m1Err=np.sqrt(m1)
p1Err=np.sqrt(p1)

comboErr=np.append(m1Err,p1Err)

startParam=[lam1, d01 ,deltan1, per1, y01]

popt, pcov = opti.curve_fit(combinedFunction, comboX, comboY, startParam) 
print popt 

lam,d0,deltan,per,y0 = popt

y_fit_1 = rM1(theta,lam,d0,deltan,per,y0) # first data set, first equation
y_fit_2 = rP1(theta,lam,d0,deltan,per,y0) # second data set, second equation

plt.plot(comboX, comboY, '.') # plot the raw data
plt.plot(pos, y_fit_1,'b') # plot the equation using the fitted parameters
plt.plot(pos, y_fit_2,'r') # plot the equation using the fitted parameters
plt.show()

print('lam,d0,deltan,per,y0:', popt)

2 个答案:

答案 0 :(得分:0)

我认为这个示例会有所帮助,它为两个数据集和两个函数提供了一个共享参数,只需将所有参数共享即可,这应该是您所需要的。

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

y1 = np.array([ 16.00,  18.42,  20.84,  23.26])
y2 = np.array([-20.00, -25.50, -31.00, -36.50, -42.00])
comboY = np.append(y1, y2)

x1 = np.array([5.0, 6.1, 7.2, 8.3])
x2 = np.array([15.0, 16.1, 17.2, 18.3, 19.4])
comboX = np.append(x1, x2)

if len(y1) != len(x1):
    raise(Exception('Unequal x1 and y1 data length'))
if len(y2) != len(x2):
    raise(Exception('Unequal x2 and y2 data length'))


def function1(data, a, b, c): # not all parameters are used here, c is shared
        return a * data + c

def function2(data, a, b, c): # not all parameters are used here, c is shared
        return b * data + c


def combinedFunction(comboData, a, b, c):
    # single data reference passed in, extract separate data
    extract1 = comboData[:len(x1)] # first data
    extract2 = comboData[len(x1):] # second data

    result1 = function1(extract1, a, b, c)
    result2 = function2(extract2, a, b, c)

    return np.append(result1, result2)


# some initial parameter values
initialParameters = np.array([1.0, 1.0, 1.0])

# curve fit the combined data to the combined function
fittedParameters, pcov = curve_fit(combinedFunction, comboX, comboY, initialParameters)

# values for display of fitted function
a, b, c = fittedParameters

y_fit_1 = function1(x1, a, b, c) # first data set, first equation
y_fit_2 = function2(x2, a, b, c) # second data set, second equation

plt.plot(comboX, comboY, 'D') # plot the raw data
plt.plot(x1, y_fit_1) # plot the equation using the fitted parameters
plt.plot(x2, y_fit_2) # plot the equation using the fitted parameters
plt.show()

print('a, b, c:', fittedParameters)

答案 1 :(得分:0)

如果您不介意使用包装scipy的其他软件包,那么我编写的symfit软件包将使您能够非常简单地完成此操作。示例代码:

from symfit import variables, parameters, Fit

# These are your datasets
xdata = np.array([...])
ydata = np.array([...])
zdata = np.array([...])

a, b, c, d, e = parameters('a, b, c, d, e')
x, y, z = variables('x, y, z')

model_dict = {
    y: a * x + b * x**2 + ...,
    z: a / x + b / x**2 + ...
}

fit = Fit(model_dict, x=xdata, y=ydata, z=zdata)
fit_result = fit.execute()
print(fit_result)

就是这样!我在这里假设两个数据集共享相同的x轴,但即使不是这种情况。现在将对参数进行优化,以为该方程组提供最佳解决方案。

有关更多信息,您可以找到文档here