【问题标题】:Fitting with Lmfit several datsets with shared parameters and one fixed parameter for each dataset使用 Lmfit 拟合多个具有共享参数的数据集和每个数据集的一个固定参数
【发布时间】:2017-01-20 14:55:18
【问题描述】:

我是 python 的初学者,但遇到了一个问题。 我想使用 lmfit 模块将函数拟合到 .csv 文件中的 3 组 (x, y) 数据,其中包含一些共享参数 (a,b,d) 和一个固定的单个参数 (c)。 我的数据格式如下: x1 y1 x2 y2 x3 y3 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..

.. .. .. .. .. ..

这是一个指数函数的示例,以及我尝试拟合每个数据集并进行绘图的尝试。我在定义全局残差以及为 c 参数的每个数据集定义一个固定值时遇到问题。这是我到目前为止所得到的:

 import numpy as np
import pandas as pd
from lmfit import minimize, Parameters, report_fit
import matplotlib.pyplot as plt


#Load data
df=pd.read_csv('mydata.csv')
df[['x1', 'y1', 'x2', 'y2', 'x3','y3']][:6]

# set up the data
xs = np.array(df[df.columns[0::2]]) 
ys = np.array(df[df.columns[1::2]]) 

#define function
def biexp(xs,a,b,c,d):
    return a*np.exp(-xs*b*c)+(1-a)*np.exp(-xs*d*c)
 
 #Define a function that calculates biexp for data set i
def biexp_dataset(params, i, xs):
    a = params['a_%i' % (i+1)].value
    b = params['b_%i' % (i+1)].value
    c = params['c_%i' % (i+1)].value
    d = params['d_%i' % (i+1)].value
    return biexp(xs,a,b,c,d)
    
#Define the real function to minimize, which calculates the total residual for all fits, modeled by biexp function
"""Where I'm stuck"""
def objective(params, xs,ys):
    nys, nxs= df.shape[1]/2
    resid = 0.0*ys[:]
    # make residual per data set
    for i in range(nys):
       resid = ys[:, i] - biexp_dataset(params,i,xs)
    # now flatten this to a 1D array, as minimize() needs
    return resid.flatten()

#Define parameters
fit_params = Parameters()
for i in range(df.shape[1]/2): 
    fit_params.add( 'a_%i' % (i+1), value=1, min=0,  max=9,vary=True)
    fit_params.add( 'b_%i' % (i+1), value=0.3, min=0.0, vary=True)
    fit_params.add( 'd_%i' % (i+1), value=0.5, min=0.0,  vary=True)
"""How can I define c for each data sets?"""
"""Iwant for x1,y1 => c1=2; x2,y2=>c2=0.4; x3,y3=>c3=5, for example"""

#  constrain all values of a,b and d to have the same value
for i in (2, 3):
    fit_params['a_%i' % i].expr='a_1'
    fit_params['b_%i' % i].expr='b_1'
    fit_params['d_%i' % i].expr='d_1'

      
# run the global fit to all the data sets
result=minimize(objective, fit_params, args=(xs, ys))
report_fit(result.params)

# plot the data sets and fits
plt.figure()
for i in range(df.shape[1]/2):
    y_fit = biexp_dataset(fit_params, i, xs)
    plt.plot(xs[:,i], ys[:, i], 'o', xs[:,i], y_fit, '-')

plt.show()

所以基本上我要问的是:如何为每个数据集定义一个固定的 c 参数值? c1=0.4;例如c2=1;c3=5

我在目标定义中做错了什么,因为当我运行代码时它指出:TypeError: can't multiply sequence by non-int of type 'float'

任何帮助将不胜感激......

更新

所以我使用我想要拟合的真实函数编写了一些新代码(并且我已经使用 originLab 中的全局拟合选项进行了拟合)。因此,我的数据集共享相同的 D1、D2、tau1 和 tau2。然而,模型作为一个新变量固定,即实验时间(t_exps)。现在我的代码没有任何错误,但我得到的不是六个数据集的 6 条拟合曲线,而是 36 条曲线拟合。我迷路了......我的代码有什么问题:

import numpy as np
import pandas as pd
from lmfit import minimize, Parameters, report_fit
import matplotlib.pyplot as plt

#set up the data
df=pd.read_excel('BTMS_hex.xlsx')

df = df.dropna() #drop rows that have invalid values (extra line in data file)
# set up the data
xs = np.array(df[df.columns[0::2]]).astype(float)
ys = np.log(np.array(df[df.columns[1::2]]).astype(float))
t_exps = [0.04857, 0.0989, 0.14923, 0.1993, 0.49957, 0.99957]


#Create function
def karger(xs,D1,D2,tau1,tau2,texp):
    term1=D1+D2+(1/(xs/texp))*((1/tau1)+(1/(tau2)))
    term2=np.sqrt(((D1-D2+(1/(xs/texp))*((1/tau1)+(1/(tau2))))**2)+(4/(((xs/texp)**2)*tau1*tau2)))
    DA=0.5*(term1-term2)
    DB=0.5*(term1+term2)
    P1=tau1/(tau1+tau2)
    P2=1-P1
    CB=(P1*D1+P2*D2-DA)/(DB-DA)
    return np.log((1-CB)*np.exp(-xs*DA)+CB*np.exp(-xs*DB))

def karger_dataset(params, xs,texp):
    D1 = params['D1'].value
    D2 = params['D2'].value
    tau1 = params['tau1'].value
    tau2 = params['tau2'].value 
    return karger(xs, D1,D2,tau1,tau2,texp)
    
def objective(params, xs,ys):
    resid = np.array([])
    for i in range(xs.shape[1]):
        y_pred = karger_dataset(params, xs[:,i],t_exps[i])
        resid=np.concatenate((resid,(ys[:, i] - y_pred)))     
    return resid

#Define parameters
fit_params = Parameters()
fit_params.add( 'D1', value=2E-1,min=0, vary=False)
fit_params.add( 'D2', value=1E-2, min=0, vary=True)
fit_params.add( 'tau1', value=8.2, min=0, vary=True)
fit_params.add( 'tau2', value=0.5, min=0,  vary=True)

# run the global fit to all the data sets
result=minimize(objective, fit_params, args=(xs, ys))
report_fit(result.params)

print result.residual

# plot the data sets and fits
plt.figure()
for i in range(df.shape[1]/2):
    y_fit = karger_dataset(fit_params, xs,t_exps[i])
    plt.plot(xs[:,i], ys[:, i], 'o', xs[:,i], y_fit, '-')

"plt.yscale('log')"
plt.axis([0,1600, -10,0.1])
plt.savefig('books_read.png')

【问题讨论】:

    标签: curve-fitting curve least-squares


    【解决方案1】:

    对于

    所以基本上我要问的是:我如何定义一个固定的 c 参数 每个数据集的价值? c1=0.4;例如c2=1;c3=5

    为什么不这样做

    fit_params.add('c1', value=0.4, vary=False)
    fit_params.add('c2', value=1.0, vary=False)
    fit_params.add('c3', value=5.0, vary=False)
    

    在定义其他参数的for i in range(df.shape[1]/2): 循环之后?

    对于

    自从我跑步以来,我在目标定义中做错了什么 它声明的代码:TypeError: can't multiply sequence by non-int of type 'float'

    如果没有看到完整的回溯(这可能会告诉您发生此异常的代码行),我猜想某处有一个列表而不是一个 numpy 数组乘以一个浮点数。

    我不太明白为什么您会收到该错误而不是“我找不到参数 'c1'”错误,但这表明它可能在您开始锻炼之前就发生了。完整的回溯会澄清这一点。

    【讨论】:

    • 更新与原始问题完全无关,您甚至没有说明较早的答案是否有助于解决该问题。
    • 更新与原来的问题完全无关,你甚至没有说早期的答案是否有帮助。 Lmfit 有一个邮件列表:请使用它。没有回溯和输出,只看代码,我们只能猜测问题所在。在进一步的帖子中,给出一个最小的示例、全文输出和完整的回溯。我不明白您所说的“36 曲线拟合”是什么意思。有一个目标函数和一个最小化()调用:你正在做一个适合。你循环 xs.shape[1] - 必须是数据集的数量,大概是 6 个。不是吗?
    • ^感谢您的回答。我将发布一个更详细的问题。要回答是,我只有一个函数可以最小化,并且有 6 个数据集 (x1,y1,...x6,y6),每个数据集都有一个 texp(texp1,texp2...texp6)。您之前的回答让我走上了定义文本的正确轨道,对此我非常感激。
    【解决方案2】:

    【讨论】:

      猜你喜欢
      • 2013-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-26
      • 1970-01-01
      • 1970-01-01
      • 2019-12-04
      • 2018-12-09
      相关资源
      最近更新 更多