【问题标题】:Python - calculating trendlines with errorsPython - 计算有错误的趋势线
【发布时间】:2011-08-24 06:33:53
【问题描述】:

所以我将一些数据存储为两个列表,并使用

plot(datasetx, datasety)

然后我设置一条趋势线

trend = polyfit(datasetx, datasety)
trendx = []
trendy = []

for a in range(datasetx[0], (datasetx[-1]+1)):
    trendx.append(a)
    trendy.append(trend[0]*a**2 + trend[1]*a + trend[2])

plot(trendx, trendy)

但我有第三个数据列表,这是原始数据集中的错误。我很擅长绘制误差线,但我不知道如何使用它,如何找到多项式趋势线系数中的误差。

假设我的趋势线是 5x^2 + 3x + 4 = y,那么 5、3 和 4 的值肯定存在某种错误。

有没有使用 NumPy 的工具可以为我计算这个?

【问题讨论】:

标签: python numpy trendline


【解决方案1】:

我认为你可以使用scipy.optimizedocumentation)的curve_fit功能。一个基本的用法示例:

import numpy as np
from scipy.optimize import curve_fit

def func(x, a, b, c):
    return a*x**2 + b*x + c

x = np.linspace(0,4,50)
y = func(x, 5, 3, 4)
yn = y + 0.2*np.random.normal(size=len(x))

popt, pcov = curve_fit(func, x, yn)

根据文档,pcov 给出:

popt 的估计协方差。对角线提供方差 的参数估计。

因此,您可以通过这种方式计算系数的误差估计。要获得标准差,您可以取方差的平方根。

现在你在系数上有一个错误,但它只是基于 ydata 和拟合之间的偏差。如果您还想解决 ydata 本身的错误,curve_fit 函数提供了sigma 参数:

sigma : 无或 N 长度序列

如果不是None,它代表ydata的标准差。这 向量,如果给定,将用作最小二乘中的权重 问题。

一个完整的例子:

import numpy as np
from scipy.optimize import curve_fit

def func(x, a, b, c):
    return a*x**2 + b*x + c

x = np.linspace(0,4,20)
y = func(x, 5, 3, 4)
# generate noisy ydata
yn = y + 0.2 * y * np.random.normal(size=len(x))
# generate error on ydata
y_sigma = 0.2 * y * np.random.normal(size=len(x))

popt, pcov = curve_fit(func, x, yn, sigma = y_sigma)

# plot
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
ax.errorbar(x, yn, yerr = y_sigma, fmt = 'o')
ax.plot(x, np.polyval(popt, x), '-')
ax.text(0.5, 100, r"a = {0:.3f} +/- {1:.3f}".format(popt[0], pcov[0,0]**0.5))
ax.text(0.5, 90, r"b = {0:.3f} +/- {1:.3f}".format(popt[1], pcov[1,1]**0.5))
ax.text(0.5, 80, r"c = {0:.3f} +/- {1:.3f}".format(popt[2], pcov[2,2]**0.5))
ax.grid()
plt.show()


然后是别的,关于使用 numpy 数组。使用 numpy 的主要优点之一是您可以避免 for 循环,因为对数组的操作按元素应用。因此,您示例中的 for 循环也可以按如下方式完成:

trendx = arange(datasetx[0], (datasetx[-1]+1))
trendy = trend[0]*trendx**2 + trend[1]*trendx + trend[2]

我使用arange 代替范围,因为它返回一个numpy 数组而不是一个列表。 这种情况下也可以使用numpy函数polyval

trendy = polyval(trend, trendx)

【讨论】:

    【解决方案2】:

    我无法找到任何方法来获取 numpy 或 python 内置的系数中的错误。我有一个简单的工具,它是根据 John Taylor 的 An Introduction to Error Analysis 的第 8.5 和 8.6 节编写的。也许这对您的任务来说已经足够了(注意默认的回报是方差,而不是标准差)。由于显着的协方差,您可能会得到较大的错误(如提供的示例中所示)。

    def leastSquares(xMat, yMat):
    '''
    Purpose
    -------
    Perform least squares using the procedure outlined in 8.5 and 8.6 of Taylor, solving
    matrix equation X a = Y
    
    Examples
    --------
    >>> from scipy import matrix
    >>> xMat = matrix([[  1,   5,  25],
                       [  1,   7,  49],
                       [  1,   9,  81],
                       [  1,  11, 121]])
    >>> # matrix has rows of format [constant, x, x^2]
    >>> yMat = matrix([[142],
                       [168],
                       [211],
                       [251]])
    >>> a, varCoef, yRes = leastSquares(xMat, yMat)
    >>> # a is a column matrix, holding the three coefficients a, b, c, corresponding to
    >>> # the equation a + b*x + c*x^2
    
    Returns
    -------
    a: matrix
        best fit coefficients
    varCoef: matrix
        variance of derived coefficents
    yRes: matrix
        y-residuals of fit 
    '''
    xMatSize = xMat.shape
    numMeas = xMatSize[0]
    numVars = xMatSize[1]
    
    xxMat = xMat.T * xMat
    xyMat = xMat.T * yMat
    xxMatI = xxMat.I
    
    aMat = xxMatI * xyMat
    yAvgMat = xMat * aMat
    yRes = yMat - yAvgMat
    
    var = (yRes.T * yRes) / (numMeas - numVars)
    varCoef = xxMatI.diagonal() * var[0, 0]
    
    return aMat, varCoef, yRes
    

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 1970-01-01
      • 2018-07-18
      • 1970-01-01
      • 2020-01-16
      • 2011-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多