【问题标题】:How to fit multiple datasets which have a combination of shared and non-shared parameters如何拟合具有共享和非共享参数组合的多个数据集
【发布时间】:2016-11-03 14:48:18
【问题描述】:

我正在尝试拟合多个数据集,这些数据集应该有一些变量在数据集之间共享,而其他变量则不是。但是我不确定我需要采取哪些步骤来做到这一点。下面我展示了我正在尝试使用的方法(从“问题从这里开始”不起作用,它只是为了说明目的)。

In this answer 有人能够共享参数arcoss 数据集是否有某种方法可以调整,以便我也可以拥有一些非共享参数?

有没有人知道我该如何实现这一目标,或者有人可以建议一种更好的方法来实现相同的结果?谢谢。

import numpy as np
from scipy.stats import gamma
import matplotlib.pyplot as plt
import pandas as pd
from lmfit import minimize, Minimizer, Parameters, Parameter, report_fit, Model


# Create datasets to fit
a = 1.99
start = gamma.ppf(0.001, a)
stop = gamma.ppf(.99, a)
xvals = np.linspace(start, stop, 100)
yvals = gamma.pdf(xvals, a)
data_dict = {}
for dataset in range(4):
    name = 'dataset_' + str(dataset)
    rand_offset = np.random.uniform(-.1, .1)
    noise = np.random.uniform(-.05, .05,len(yvals)) + rand_offset

    data_dict[name] = yvals + noise
df = pd.DataFrame(data_dict)

# Create some non-shared parameters
non_shared_param1 = np.random.uniform(0.009, .21, 4)
non_shared_param2 = np.random.uniform(0.01, .51, 4)

# Create the independent variable
ind_var = np.linspace(.001,100,100)

# Create a model
def model_func(time, Qi, at, vw, R, rhob_cb, al, NSP1, NSP2):
    Dt = at * vw
    Dl = al * vw

    t = time

    first_bot = 8 * np.pi * t * rhob_cb
    sec_bot = np.sqrt((np.pi * (Dl * R) * t))
    exp_top = R * np.power((NSP1 - ((t * vw)/R)), 2)
    exp_bot = 4 * Dl * t
    exp_top2 = R * np.power(NSP2, 2)
    exp_bot2 = 4 * Dt * t
    return (Qi / first_bot * sec_bot) * np.exp(- (exp_top / exp_bot) - (exp_top2 / exp_bot2))

model = Model(model_func)

### Issues begin here ###

all_results = {}
index = 0
for col in df:
    # This block assigns the correct non-shared parameter for the particular fit
    nsp1 = non_shared_param1[index]
    nsp2 = non_shared_param2[index]
    index += 1

    params = Parameters()
    at = 0.1 
    al = 0.15
    vw = 10**-4
    Dt = at * vw
    Dl = al * vw

    # Non-shared parameters
    model.set_param_hint('NSP1', value = nsp1)
    model.set_param_hint('NSP2', value = nsp2)

    # Shared and varying parameters
    model.set_param_hint('vw', value =10**-4, min=10**-10)
    model.set_param_hint('at', value =0.1)
    model.set_param_hint('al', value =0.15)

    # Shared and fixed parameters
    model.set_param_hint('Qi', value = 1000, vary = True)
    model.set_param_hint('R', value = 1.7, vary = True)
    model.set_param_hint('rhob_cb', value =2895, vary = True)

    # One set of parameters should be returned
    result = model.fit(df[col], time = ind_var)

    all_results[index] = result

【问题讨论】:

  • 如果您想预测另一个数据集的样本类别,您必须将该数据集的特征集合投影到训练分类器的数据集的特征集合之上。换句话说,您不能在训练某些特征后对其他不同的特征进行测试!
  • @MMF 对不起,我不认为我关注。我的不同数据集是从不同空间位置对同一事件的观察。然后,我将使用考虑距离的相同公式来拟合数据。所以我需要有一些非共享参数(空间),但每个观察点的“未知”参数应该是相同的。本质上,我想尝试非共享参数的每种组合并返回在所有观察中产生最小残差的组合。我在问题中概述的方法是否完全错误?感谢您的帮助!

标签: python lmfit


【解决方案1】:

使用 lmfit 的拟合总是使用一个参数对象的实例,它不需要多个参数对象。

为了同时使用相似模型拟合多个数据集(可能是相同的数学模型,但期望每个模型的参数值不同),您需要有一个目标函数来连接来自不同组件模型的残差。这些模型中的每一个都必须具有从 Parameters() 的单个实例中获取的参数,每个参数都有一个唯一的名称。

因此,要使用相同的函数拟合 2 个数据集(让我们使用 Gaussian,参数为“center”、“amplitude”和“sigma”),您可以将 Parameters 定义为

params =  Parameters()
params.add('center_1',    5., vary=True)
params.add('amplitude_1', 10., vary=True)
params.add('sigma_1',    1.0, vary=True
params.add('center_2',    8., vary=True)
params.add('amplitude_2', 3., vary=True)
params.add('sigma_2',    2.0, vary=True)

然后使用'center_1'、'amplitude_1'和'sigma_1'计算第一个数据集的模型,用'center_2'等计算第二个数据集的模型,可能是这样

def residual(params, x, datasets):
    model1 = params['amplitude_1'] * gaussian(x, params['center_1'], params['sigma_1'])
    model2 = params['amplitude_2'] * gaussian(x, params['center_2'], params['sigma_2']

    resid1 = datasets[0] - model1
    resid2 = datasets[1] - model2
    return np.concatenate((resid1, resid2))

fit = lmfit.minimize(residual, params, fcn_args=(x, datasets))

您可能从中可以看出,默认情况下参数值是独立的。为了共享要在不同数据集中使用的参数值,您必须明确地执行此操作(如您提供的链接答案所示)。

例如,如果你想要求sigma的值相同,不会改变残差函数,只需将上面的参数定义为:

params.add('sigma_2', expr='sigma_1')

您可能需要两个幅度来增加某个值:

params.add('amplitude_2', expr='10 - amplitude_1')

或者您可能希望确保 'center_2' 大于 'center_1',但要确定合适的数量:

params.add('center_offset', value=0.5, min=0)
params.add('center_2',  expr='center_1 + center_offset')

这些都是绑定参数值的方法。默认情况下,它们是独立的。当然,您也可以有一些在所有模型中使用的参数(例如,只需调用参数“sigma”并将其用于所有模型)。

【讨论】:

    猜你喜欢
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    相关资源
    最近更新 更多