【问题标题】:Problems with curve_fit fitting highly correlated datacurve_fit 拟合高度相关数据的问题
【发布时间】:2017-12-02 06:53:57
【问题描述】:

对于我的学士论文,我正在做一个项目,我想对一些数据进行拟合。问题有点复杂,但我在这里尽量减少问题:

我们有三个数据点(可用的理论数据很少),但这些点高度相关。

使用curve_fit来拟合这些点,我们得到了一个可怕的拟合结果,正如你在这张图片中看到的那样。 (通过手动改变拟合参数可以很容易地改善拟合)。

我们的拟合结果具有相关性(蓝色)和被忽略的相关性(橙色):

当我们使用更多参数时,结果会变得更好(因为到那时拟合基本上表现得像求解)。

我的问题:为什么会发生这种行为? (我们使用我们自己的最小二乘算法来解决我们的具体问题,但它也遇到了同样的问题)。这是一个数值问题,还是curve_fit有什么好的理由来展示这个解决方案?

我很高兴能很好地解释为什么我们不能使用“仅 2 个”参数来拟合这些高度相关的 3 个数据点。

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
plt.rcParams['lines.linewidth'] = 1

y = np.array([1.1994, 1.0941, 1.0047])
w = np.array([1, 1.08, 1.16])
cor = np.array([[1, 0.9674, 0.8812],[0.9674, 1, 0.9523], [0.8812, 0.9523, 1]])
s = np.array([0.0095, 0.0104, 0.0072])

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

cov = np.zeros((3,3))
for i in range(3):
    for j in range(3):
        cov[i,j] = cor[i,j] * s[i] * s[j]

A1, B1 = curve_fit(f, w, y, sigma=cov)
A2, B2 = curve_fit(f, w, y)

plt.plot(w, f(w, *A1))
plt.plot(w, f(w, *A2))

plt.scatter(w, y)
plt.show()

【问题讨论】:

  • 我不明白这个问题(顺便说一句:代码没有在我的机器上运行,因为cov 似乎格式错误)。拟合效果很好,也适用于两个参数 (A2)。那么当您确定A1 时,您到底想做什么?
  • 拟合 A2 确实可以正常工作,因为它不包括相关性。在A1 中,我想执行加权最小二乘拟合,因此我将协方差矩阵传递给curve_fit。 (代码对我有用,使用 numpy 1,11,2)
  • 我的错;我确实有一个过时的 numpy/scipy 版本。文档说:A 2-d sigma should contain the covariance matrix of errors in ydata.这是你的传球吗?
  • 确实,如果我对此不确定,我很抱歉。我确实传递了 y 数据的协方差矩阵。我不想浪费任何信息,因为我只有 3 个数据点,因此尝试包含有关错误和协方差的所有信息
  • 好了,不马上看,怎么了;如果你通过sigma=s,它看起来很好。

标签: python scipy physics curve-fitting data-science


【解决方案1】:

这不是一个数字问题。 “问题”是协方差矩阵的非对角项都是正数且相对较大。这些决定了拟合误差之间的相关性,所以如果所有项都是正的,那么你就是说所有的误差都是正相关的。如果一个很大,那么其他的也往往会很大,并且具有相同的符号。

这是一个与您的示例类似的示例,带有协方差矩阵

        [2.0  1.3  0.0]
sigma = [1.3  2.0  1.3]
        [0.0  1.3  2.0]

(这个矩阵的条件数是23.76,所以我们不应该期望任何数值问题。)

虽然第一个点和第三个点的协方差为0,但第一个点和第二个点之间的协方差是1.3,第二个和第三个点之间的协方差是1.3,而1.3是方差比较大的一部分,都是2。所以它会如果拟合模型中的所有错误都具有相同的符号,那就不足为奇了。

此脚本对三个点进行拟合并绘制数据和拟合线。

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


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


x = np.array([1, 2, 3])
y = np.array([2, 0.75, 0])
sig = np.array([[2.0, 1.3, 0.0],
                [1.3, 2.0, 1.3],
                [0.0, 1.3, 2.0]])

params, pcov = curve_fit(f, x, y, sigma=sig)

y_errors = f(x, *params) - y

plt.plot(x, y, 'ko', label="data")
plt.plot(x, f(x, *params), linewidth=2.5, label="fitted curve")
plt.vlines(x, y, f(x, *params), 'r')

for k in range(3):
    plt.annotate(s=r"$e_{%d}$" % (k+1), xy=(x[k]-0.05, y[k]+0.5*y_errors[k]), ha='right')

plt.xlabel('x')
plt.ylabel('y')
plt.axis('equal')
plt.grid()
plt.legend(framealpha=1, shadow=True)
plt.show()

正如您在图中看到的,所有错误都具有相同的符号。

我们可以通过考虑另一个协方差矩阵来确认这个推理,

        [ 2.0   1.3  -1.0]
sigma = [ 1.3   2.0  -1.3]
        [-1.0  -1.3   2.0]

在这种情况下,所有非对角项的量级都相对较大。第一个和第二个误差之间的协方差为正,第二个和第三个以及第一个和第三个之间的协方差为负。如果这些非对角项相对于方差足够大,我们应该期望前两个点的误差符号相同,而第三个误差的符号与前两个点相反。

下面是sig改成上述矩阵时脚本生成的图:

错误显示了预期的模式。

【讨论】:

  • 很好的解释! +1
  • 非常感谢!这个解释真的很有帮助,尽管在使用 GLS 时它仍然是一个值得记住的有趣行为。
猜你喜欢
  • 2012-06-07
  • 2018-03-29
  • 2020-06-08
  • 2014-01-20
  • 1970-01-01
  • 2017-03-17
  • 2019-02-12
  • 2021-11-05
  • 2015-09-26
相关资源
最近更新 更多