将数据拟合到3次多项式

时间:2011-08-01 17:25:41

标签: c++ math statistics

我正在编写一个C ++程序,其中我有独立和依赖数据的向量,我想要适合三次函数。但是,我无法生成适合我数据的多项式。

部分问题在于我无法使用各种数字包,例如GSL(长篇故事);对我的情况来说甚至可能有点矫枉过正。对于最小二乘拟合,我不需要非常通用的解决方案。我特别希望将我的数据拟合为三次函数。我可以访问索尼的矢量库,它支持4x4矩阵,可以计算它们的逆,等等。

在Scilab中对此进行原型设计时,我使用了以下函数:

function p = polyfit(x, y, n)
    m = length(x);
    aa = zeros(m, n+1)
    aa(:,1) = ones(m,1)
    for k = 2:n+1
        aa(:,k) = x.^(k-1)
    end
    p = aa\y
endfunction

不幸的是,这并不适合我当前的环境。以上示例需要支持M x N + 1维的矩阵。就我而言,那是M x 4,其中M取决于我有多少样本数据。还有左分裂的问题。我需要一个矩阵库来支持任意维矩阵的逆矩阵。

是否存在最小二乘算法,我可以避免计算aa \ y,或者至少将其限制为4x4矩阵?我想我正在尝试将上述算法重写为一个更简单的情况,适用于拟合三次多项式。我不是在寻找代码解决方案,但如果有人能指出我正确的方向,我会很感激。

3 个答案:

答案 0 :(得分:12)

Here是我正在处理的页面,尽管该页面本身并未直接解决您的问题。我的答案摘要是:

  

如果你不能直接使用Nx4矩阵,那么就做那些矩阵   计算“手动”直到你遇到问题,直到只有4x4或更小的矩阵。在这个答案中,我将概述如何“手动”进行所需的特定矩阵计算。

-

假设您有一堆数据点(x1,y1)...(xn,yn),并且您正在寻找最适合这些点的三次方程y = ax^3 + bx^2 + cx + d

然后按照上面的链接,你会写下这个等式:

enter image description here

我会为这些矩阵写AxB。然后按照我上面的链接,您希望乘以A的转置,它将为您提供4x4矩阵A T * {{1你可以反转。在方程式中,以下是计划:

  

A * x = B .................... [我们开始的时候]

     

(A T * A)* x = A T * B ..... [乘以A T ]

     

x =(A T * A) -1 * A T * B ... [乘以A的倒数< sup> T * A]

你说你很乐意反转A矩阵,所以如果我们可以编写一种方法来获取这些矩阵而不实际使用矩阵对象,我们应该没问题。

所以,这是一个方法,虽然它可能有点像为你的口味制作自己的矩阵库。 :)

  • 为4x4矩阵的16个条目中的每个条目写一个显式方程。 4x4条目(我以(0,0)开头)由。给出 x 1 i * x 1 j + x 2 i < / sup> * x 2 j + ... + x N i * x N < /子> Ĵ

  • 使用矩阵库反转4x4矩阵。那是((i,j) T * A -1

  • 现在我们所需要的只是A T * A,这是一个4x1矩阵。它的第i个条目由x 1 i * y 1 + x 2 i < / sup> * y 2 + ... + x N i * y N

  • 用手工创建的4x1矩阵乘以我们手工创建的4x4矩阵(B T * A -1 A T * A获取立方体的最小二乘系数的4x1矩阵。

祝你好运!

答案 1 :(得分:9)

是的,我们可以将问题限制为使用“4x4矩阵”进行计算。即使对于M个数据点,立方体的最小二乘拟合仅需要四个未知数中的四个线性方程的解。假设所有x坐标都是不同的,则系数矩阵是可逆的,因此原则上系统可以通过反转系数矩阵来求解。我们假设M大于4,通常是最小二乘拟合的情况。

这是Maple的一篇文章,Fitting a cubic to data,它几​​乎完全隐藏了正在解决的内容的细节。一阶最小标准(关于系数的一阶导数作为平方和误差的参数)得到四个线性方程,通常称为normal equations

您可以在代码中“组合”这四个方程式,然后应用矩阵逆或更复杂的解决方案策略。显然,您需要以某种形式存储数据点。一种可能性是两个线性阵列,一个用于x坐标,一个用于y坐标,长度M都是数据点的数量。

NB:我将根据基于1的数组下标来讨论这个矩阵程序集。多项式系数实际上是一个应用程序,其中基于0的数组下标使事情变得更清晰和简单,但是用C或任何其他有利于基于0的下标的语言重写它是留给读者的练习。

正规方程的线性系统最容易用矩阵形式表示,参考Mx4数组A,其条目是x坐标数据的幂:

A(i,j)=第i个数据点的x坐标上升到幂j-1

设A'表示A的转置,因此A'A是4x4矩阵。

如果我们让d是一个长度为M的列,包含数据点的y坐标(按照给定的顺序),那么正规方程组就是这样:

A'A u = A'd

其中u = [p0,p1,p2,p3]'是具有最小二乘拟合的三次多项式的系数列:

P(x)= p0 + p1 * x + p2 * x ^ 2 + p3 * x ^ 3

您的异议似乎集中在存储和/或操纵Mx4阵列A或其转置的难度上。因此,我的答案将集中在如何组装矩阵A'A和A列而不一次明确地存储所有A。换句话说,我们将隐式地执行指示的矩阵 - 矩阵和矩阵 - 向量乘法,以获得可以解决的4x4系统:

C u = f

如果你认为条目C(i,j)是A的第i行与A的第j列的乘积,再加上A'的第i行实际上只是第i个转置的事实A栏,应该清楚:

所有数据点的C(i,j)= SUM x ^(i + j-2)

这肯定是通过使用基于0的下标简化博览会的地方!

积累矩阵C的条目可能是有意义的,矩阵C的条目仅取决于i + j的值,即所谓的Hankel matrix,在长度为7的线性数组中,这样:

W(k)=所有数据点的SUM x ^ k

其中k = 0,..,6。 4x4矩阵C具有“条纹”结构,这意味着只显示这七个值。循环遍历数据点的x坐标列表,可以在W的相应条目中累积每个数据点的每个幂的适当贡献。

可以使用类似的策略来组合列f = A'd,即循环数据点并累积以下四个总和:

f(k)=所有数据点的SUM(x ^ k)* y

其中k = 0,1,2,3。 [当然,在上面的总和中,值x,y是公共数据点的坐标。]

警告:这满足了仅使用4x4矩阵的目标。然而,人们通常试图避免显式形成正规方程的系数矩阵,因为这些矩阵通常是数值分析中被称为病态的。特别是当x坐标紧密间隔的情况下,当试图通过反转系数矩阵来解决系统时,会导致困难。

解决这些正规方程的一种更复杂的方法是conjugate gradient method on the normal equations,这可以通过计算矩阵向量积A u和A'v的代码一次完成一个条目(使用我们所说的)以上关于A)的条目。

共轭梯度法的准确性通常是令人满意的,因为它具有自然的迭代方法,尤其是当人们可以用一点额外的精度计算出所需的点积时。

答案 2 :(得分:3)

出于稳定性原因,您永远不应该进行完整的矩阵求逆。进行LU分解和前后替换。否则其他解决方案就是现货。