【问题标题】:Using curve_fit to estimate common model parameters over datasets with different sizes使用curve_fit估计不同大小数据集的常见模型参数
【发布时间】:2021-07-30 17:44:59
【问题描述】:

我正在研究一个曲线拟合问题,我打算在多个大小不等的数据集上全局估计共享模型参数。我从下面链接中的代码开始工作,其中线性回归 y = a*x + b 的常见 a 参数是在三个不同的 y 向量和一个共同的 x 向量上估计的。 How to use curve_fit from scipy.optimize with a shared fit parameter across multiple datasets?

我设法使代码示例适应更一般的情况,使用三个不同的 x 向量,一个对应于每个 y 数据向量。但是,当我想进一步扩展它以使其也适用于大小不等的数据集时,我遇到了以下错误:“ValueError: setting an array element with a sequence.”。

请在下面找到代码示例。非常感谢任何帮助!

干杯

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

x = [[0, 1, 2, 3],
[0.2, 1.2, 2.2, 3.2],
[0.3, 1.3, 2.3]]

y = [[-0.80216234,  1.41125365,  1.42565202,  2.42567754],
[ 1.34166743,  1.29731851,  2.98374731,  3.32110875],
[ 1.71398203,  3.29737756,  3.81456949]]

x = np.array(x)
y = np.array(y)


def f(x, a, b):
    return a * x + b


def g(x, a, b_1, b_2, b_3):
     return np.concatenate((f(x[0], a, b_1), f(x[1], a, b_2), f(x[2], a, b_3)))

(a, *b), _ = curve_fit(g, x, y.ravel())

for x_i, y_i, b_i in zip(x, y, b):
    plt.plot(x_i, f(x_i, a, b_i), label=f"{a:.1f}x{b_i:+.1f}")
    plt.plot(x_i, y_i, linestyle="", marker="x",  color=plt.gca().lines[-1].get_color())
plt.legend()
plt.show()

关于具有多个大小相等的 x 向量的工作示例的代码,请参见下文:

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

x = [[0, 1, 2, 3],
 [0.2, 1.2, 2.2, 3.2],
 [0.3, 1.3, 2.3, 3.3]]

y = [[-0.80216234,  1.41125365,  1.42565202,  2.42567754],
 [ 1.34166743,  1.29731851,  2.98374731,  3.32110875],
 [ 1.71398203,  3.29737756,  3.81456949, 4.25]]

x = np.array(x)
y = np.array(y)


def f(x, a, b):
    return a * x + b


def g(x, a, b_1, b_2, b_3):
    return np.concatenate((f(x[0], a, b_1), f(x[1], a, b_2),     f(x[2], a, b_3)))

(a, *b), _ = curve_fit(g, x, y.ravel())

for x_i, y_i, b_i in zip(x, y, b):
   plt.plot(x_i, f(x_i, a, b_i), label=f"{a:.1f}x{b_i:+.1f}")
   plt.plot(x_i, y_i, linestyle="", marker="x",     color=plt.gca().lines[-1].get_color())

plt.legend()
plt.show()

【问题讨论】:

  • 你能否展示多个相同大小的 x 向量的 工作 示例?问题是,numpy 既不能将x 也不能将y 解析为矩阵,因为它们的长度不相等。因此它不会解析为n \times m 矩阵,而是解析为list objectsn 维数组。
  • 亲爱的安德烈,感谢您的回复,我将编辑帖子并添加工作示例的代码,用于多个相同大小的 x 向量。

标签: python arrays numpy curve-fitting


【解决方案1】:

总的来说,我同意最小二乘拟合的含义相当复杂......一些快速的想法:

  • 如果从不同长度的数据集估计得到的b 参数,您能否确定它们同样有效?
  • 您获得的 b 参数越多,他们的估计就越不确定,因为您只优化了组合拟合性能,而不是每个单独的拟合性能
  • 我也不确定 jacobian 的数值评估在这种情况下的效果如何......可能值得实现一个自定义的 jac 函数,以精确的方式评估 jacobian
  • ...我确定还有更多我目前不知道的问题:D

不过,你当然可以欺骗scipy.optimize做你想做的事...
但是,您必须更深入一步,直接使用scipy.optimize.least_squares,而不是使用更高级别的scipy.optimize.curve_fit 函数。

通过这种方式,您可以改变计算残差的方式以接受不同长度的数据集。

...这是它如何工作的快速而简单的实现:

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

x = [[0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
     [0.2, 1.2, 2.2, 3.2],
     [0.3, 1.3, 2.3     ]]

y = [[-0.80216234, 1.41125365, 1.42565202, 2.42567754, 3, 4],
     [ 1.34166743, 1.29731851, 2.98374731, 3.32110875],
     [ 1.71398203, 3.29737756, 3.81456949            ]]


def f(x, a, b):
    return a * x + b


def fun(parameters):
    # separate a and b parameters
    a, *b = parameters

    # calculate function-results based on a shared a- and variable b- parameters
    res = (f(xi, a, bi) for (xi, bi) in zip(map(np.array, x), b))

    # calculate the residuals
    errs = []
    for i, j in zip(res, map(np.array, y)):
        errs += (i - j).tolist()
    return np.array(errs)


# set start-values
start_values = (1, 1, 2, 3)
# do the fit
a, *b = least_squares(fun, start_values).x

for x_i, y_i, b_i in zip(map(np.array, x), y, b):
    plt.plot(x_i, f(x_i, a, b_i), label=f"{a:.1f}x{b_i:+.1f}")
    plt.plot(x_i, y_i, linestyle="", marker="x", color=plt.gca().lines[-1].get_color())

plt.legend()
plt.show()

【讨论】:

  • 亲爱的 Raphael, 感谢您展示这个快速而优雅的实现!您能否澄清 .x 在 a, *b = least_squares(fun, start_values).x 行中的含义/作用?
  • 嘿,least_squares 返回一个OptimizeResult 对象...而.x 属性只会为您提供获得的参数向量!我想最好由文档解释 ;-) (docs.scipy.org/doc/scipy/reference/generated/…)
  • 太好了,谢谢!为什么需要将err转换为行中的列表? errs += (i - j).tolist()
  • @bessie 因为我们最后需要一个残差的平面列表(您也可以收集残差向量列表然后将它们连接起来,但这也会复制数据,所以我想只需附加立即获取值可能同样快速高效...)
【解决方案2】:

问题是您无法从不完整的列表中创建numpy.array。要重铸为 np.array,所有维度必须匹配,即您不能有一个空的 column 条目,因为这对 Numpy 没有意义。

在您的情况下,您还没有为数组中的 columns 之一定义一个条目(即,当其他 rows 中的最后一个 row 中有 3 个条目em> 有 4 个条目)。 Numpy 根本不会让你这样做,因为它是一个数值包,它依赖于矩形明确定义的数组来进行计算。

【讨论】:

  • 在这种情况下,定义数据结构并将其提供给 curve_fit 算法的正确方法是什么?列表对象没有“ravel”属性?
  • @bessie 您的代码没有达到曲线拟合的程度。为了同时将所有数据集拟合到模型中,它们需要具有相同的形状。在物理系统中,这意味着缺少的元素将是0,即您需要在缺少条目的地方使用0s 填充输入数据。这当然可能会对数据的拟合产生影响。
  • 在我的代码中,我们的想法是 x 数组中的每一行代表一个向量,其中包含测量样本属性的时间,而在 y 数组中,每一行代表一个包含观测值的向量。在实践中,对于不同的样本,采样时间可能不同,并且采样时间可能更少或更多,具体取决于样本。但是,仍然应该可以估计模型参数,例如不同样本的共同线性增长?
  • 是的,你可以,你只是不能像你提议的那样去做。对于独立样本,您需要进行单独的回归,然后您将获得一系列可能的参数。从那里你可以选择一个固定的a,然后我想再次重做回归。但不幸的是,您尝试的方法只有在所有输入的形状相同时才有效。
  • 这真是不幸!你能提供一些代码让我找到正确的方向吗?
猜你喜欢
  • 2013-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
相关资源
最近更新 更多