fmin_l_bfgs_b正确用于拟合模型参数

8 投票
1 回答
19639 浏览
提问于 2025-04-17 09:13

我有一些实验数据(包括y、x、t_exp和m_exp),想用受限的多变量BFGS方法来找到这些数据的“最佳”模型参数(A、B、C、D、E)。其中参数E必须大于0,其他参数没有限制。

def func(x, A, B, C, D, E, *args):
    return A * (x ** E) * numpy.cos(t_exp) * (1 - numpy.exp((-2 * B * x) / numpy.cos(t_exp))) +  numpy.exp((-2 * B * x) / numpy.cos(t_exp)) * C + (D * m_exp)

initial_values = numpy.array([-10, 2, -20, 0.3, 0.25])
mybounds = [(None,None), (None,None), (None,None), (None,None), (0, None)]
x,f,d = scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(m_exp, t_exp), bounds=mybounds)

我有几个问题:

  1. 我的模型公式func应该包含我的自变量x,还是应该从实验数据x_exp中提供,作为*args的一部分呢?
  2. 当我运行上面的代码时,出现了一个错误func() takes at least 6 arguments (3 given),我猜这应该是x和我的两个*args...我应该如何定义func呢?

补充说明:感谢@zephyr的回答,我现在明白了目标是最小化平方残差的总和,而不是实际的函数。我得到了以下可以工作的代码:

def func(params, *args):
    l_exp = args[0]
    s_exp = args[1]
    m_exp = args[2]
    t_exp = args[3]
    A, B, C, D, E = params
    s_model = A * (l_exp ** E) * numpy.cos(t_exp) * (1 - numpy.exp((-2 * B * l_exp) / numpy.cos(t_exp))) +  numpy.exp((-2 * B * l_exp) / numpy.cos(theta_exp)) * C + (D * m_exp)
    residual = s_exp - s_model
    return numpy.sum(residual ** 2)

initial_values = numpy.array([-10, 2, -20, 0.3, 0.25])
mybounds = [(None,None), (None,None), (None,None), (None,None), (0,None)]

x, f, d = scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(l_exp, s_exp, m_exp, t_exp), bounds=mybounds, approx_grad=True)

我不确定边界设置是否正确。当我为E指定(0, None)时,出现了运行标志2,表示异常终止。如果我把它设置为(1e-6, None),它运行正常,但选择了1e-6作为E。我这样指定边界是否正确?

1 个回答

14

我不想去弄清楚你使用的模型具体代表什么,所以这里给你一个简单的例子,适合拟合一条直线:

x_true = arange(0,10,0.1)
m_true = 2.5
b_true = 1.0
y_true = m_true*x_true + b_true

def func(params, *args):
    x = args[0]
    y = args[1]
    m, b = params
    y_model = m*x+b
    error = y-y_model
    return sum(error**2)

initial_values = numpy.array([1.0, 0.0])
mybounds = [(None,2), (None,None)]

scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(x_true,y_true), approx_grad=True)
scipy.optimize.fmin_l_bfgs_b(func, x0=initial_values, args=(x_true, y_true), bounds=mybounds, approx_grad=True)

第一次优化没有限制,能得到正确的结果;第二次优化有了限制,这就让它无法找到正确的参数。

你需要注意的一个重要点是,对于几乎所有的优化函数,'x'和'x0'指的是你正在优化的参数——其他的东西都是作为参数传入的。另外,你的拟合函数返回的数据类型也很重要——在这里我们需要一个单一的值,有些程序会期待一个误差向量。此外,如果你不想手动计算梯度并提供它,就需要设置approx_grad=True这个选项。

撰写回答