用矩阵运算实现最小二乘法曲线拟合算法

1. 多项式拟合函数:

y= a0 + a1x + a2x^2 + ... + akx^k    (其中k为拟合次数)

当k=1 为线性拟合 ,k=2 为二次多项式 ...  三次多项式。

2. 最小二乘原理矩阵算法原理:

X*A=Y
A=((X'*X)-1)*X'*Y

|1  X1  X1^2  ... X1^k|            |y0|
|1  X2  X2^2  ... X2^k| |a0|     |y1|
|...                              | |a1|     |.  |
|...                              | |.   |  = |.  |
|...                              | |ak|     |.  |
|1  Xn  Xn^2  ... Xn^k|            |yn|

其中 X为初始范德蒙矩阵,A 为系数向量, Y 为因变量值向量

3.计算单元算法:几个矩阵运算算法函数

1 ) 矩阵的转置运算; 2)矩阵的逆运算;3 )矩阵乘法运算

4. C++代码实现

1)矩阵乘法运算函数:

BOOL CMatrix::Mul(const Matrix &a, const Matrix &b, Matrix &c)
{
    if(a.n!=b.m)
    {
        return FALSE;
    }
    
    c.m = a.m;
    c.n = b.n;
    int i, j, k;
    for (i=0; i<a.m; i++)
    {
        for (j=0; j<b.n; j++)
        {
            for (c.p[i * c.n + j] = 0, k =0; k<a.n; k++)
            {
                c.p[i * c.n + j] += a.p[i * a.n + k] * b.p[k * b.n + j];
            }
        }
    }
    return TRUE;
}
2)矩阵转置运算函数:
void CMatrix::Trs(Matrix &a, Matrix &trs)
{
    trs.m = a.n;
    trs.n = a.m;
    
    for (int i = 0; i < a.m; i++)
    {
        for (int j = 0; j < a.n; j++)
        {
            trs.p[j * a.m + i] = a.p[i * a.n + j];
        }
    }
}

3)矩阵逆运算函数:

// 工具函数

long double CMatrix::Det(Matrix &a)
{
    long double det = 0;
    if (a.m != a.n)
    {   
        //...
        return 0;
    }
    if (a.n == 1)
    {
        det = a.p[0];
        return det;
    }
    else
    {
        for (int i = 0; i < a.n; i++)
        {
            if (i % 2 == 0)
            {
                Matrix mat;
                Adjunct(a, i, 0,mat);
                det += a.p[i * a.n] * Det(mat);
                delete mat.p;
            }
            else  
            {
                Matrix mat;
                Adjunct(a, i, 0,mat);
                det -= a.p[i * a.n] * Det(mat);
                delete mat.p;
            }
        }
    }
 
    return det;
}
 

//工具函数
void CMatrix::Adjunct(Matrix a, int indexm, int indexn,Matrix &adj)
{
    adj.SetSize(a.n - 1, a.n - 1);
    for (int i = 0; i < indexm; i++)
    {
        for (int j = 0; j < indexn; j++)
        {
            adj.p[i * (a.n - 1) + j] = a.p[i * a.n + j];
        }
        for (int k = indexn + 1; k < a.n; k++)
        {
            adj.p[i *(a.n - 1) + k -1] = a.p[i * a.n + k];
        }
    }
 
    for (int m = indexm + 1; m < a.n; m++)
    {
        for (int j = 0; j < a.n - 1; j++)
        {
            adj.p[(m - 1) * (a.n - 1) + j] = a.p[m * a.n + j];
        }
        for (int k = indexn + 1; k < a.n; k++)
        {
            adj.p[(m - 1) * (a.n - 1) + k - 1] = a.p[m * a.n + k];
        }
    }
 
}
 
// 逆运算函数
BOOL CMatrix::Inv(Matrix &a,Matrix &inv)
{
    Matrix Temp(a.m,a.n);
 
    if(a.m!=a.n)
    {
        return FALSE;
    }
 
 
    long double det = Det(a);
    if (det == 0)
    {
        return FALSE;
    }
    
    for (int i = 0; i < Temp.m; i++)
    {
        for (int j = 0; j < Temp.n; j++)
        {
            if ((i +j) % 2 == 0)
            {    
                Matrix mat;        
                Adjunct(a, i, j,mat);
                Temp.p[i * Temp.m + j] = Det(mat) / det;
                delete mat.p;
            }
            else
            {
                Matrix mat;
                Adjunct(a, i, j,mat);
                Temp.p[i * Temp.m + j] = -Det(mat) / det;
                delete mat.p;
            }
        }
    }
            
    Trs(Temp,inv);    
    return TRUE;
}

4)多项式拟合函数可以根据以上运算单元,结合矩阵运算公式:A=((X'*X)-1)*X'*Y

自由实现。

5)数据结构定义:

struct Matrix{  
    int m, n;   
    long double *p; 
    Matrix()
    {
        m = 0;
        n = 0;
        p = NULL;
    }
    Matrix(int t_m ,int t_n)
    {
        m = t_m;
        n = t_n;
        p = new long double[m*n];
    }
    void SetSize(int t_m,int t_n)
    {
        m = t_m;
        n = t_n;
        p = new long double[m*n];
    }
    ~Matrix()
    {
        if(p != NULL)
        {
        //    delete p;
        }
    }
};

posted on 2016-07-06 19:31  雁北  阅读(7212)  评论(0编辑  收藏  举报

导航