Fit the given data using the method of least squares

least square method

Purpose of data fitting:

1. Find the approximate expression y=p(x) of the functional relationship y = f(x) from a large number of experimental data (xi,yi) (i=0,1,2...m)

2. The interpolation method requires the interpolation curve to pass through each data point strictly. When n is relatively large, the difference polynomial is often a farewell polynomial, which is prone to oscillation.

3. When it is not necessary to require the approximate function y=p(x) to pass through all points, that is, yi=p(xi) i=0,1,2 ... m, only the error ri=p(xi)-yi i = 0 is required, 1,2 ... m, minimum according to a certain standard, to reflect the overall change trend of the original function and eliminate the influence of local fluctuations, such a function y=p(x) is called a fitting function.

Fundamentals of Least Squares

Find p(x) such that

insert image description here

Polynomial Fitting Procedure

    定义:对给定一组数据(xi,yi)  (i=0,1,2 ... m),求次数不超过n的多项式

insert image description here

make it satisfy

insert image description here

This curve fitting is called polynomial fitting, satisfying the above formula Pn(x) is called least squares fitting polynomial, and when n = 1, first degree polynomial is also called straight line fitting.

insert image description here

From the multivariate extremum necessary condition, we know that aj satisfies

insert image description here

Right now
insert image description here

Converted into matrix form as:
insert image description here

called normal equations or normal equations

And has the following theorem:

Theorem 1: If the points xi are different from each other, then the system of normal equations exists and is unique.

Data fitting to the given data

xi -2 -1 0 1 2
yi 0.2 0.8 2 3 4
输出拟合函数,以及平方误差

Using the least squares method for data fitting, the first step is to construct a normal equation system,

The method used here is:

Save the input data in two one-bit arrays x, y, declare the tempx[2 n] array, save Σx^i
, and use the subscript to access the sum of the corresponding power. Next, declare the tempy[n] array and save Σxi^n
yi.

variables used

double zhengGui[8][9] = {
    
     0 };
double x[8] = {
    
     0 };     //保存拟合数据xi
double y[8] = {
    
     0 };     //保存拟合数据yi
double tempx[15] = {
    
     0 };  //使用下标保存 xi^n的和
double tempy[9] = {
    
     0 };    //保存xi^n*yi

Full code:

#include<iostream>
#include<math.h>
using namespace std;
double zhengGui[8][9] = {
    
     0 };
double x[8] = {
    
     0 };     //保存拟合数据xi
double y[8] = {
    
     0 };     //保存拟合数据yi
double tempx[15] = {
    
     0 };  //使用下标保存 xi^n的和
double tempy[9] = {
    
     0 };    //保存xi^n*yi
void printGuass(double a[8][9], int n) {
    
    
    for (int i = 1; i <= n; i++) {
    
    
        for (int j = 1; j <= n + 1; j++)
            printf("%12f,", a[i][j]);
        printf("\n");
    }
}
struct Max
{
    
    
    double value = 0;
    int row = 0; //保存行
    int col = 0; //保存列
};
void SelectMainE(int n)
{
    
    
    double temp;  //记录消元时的因数
    Max max;
    for (int m = 1; m <= n; m++) {
    
    
        max.value = -1000000000;
        for (int i = m; i <= n; i++)
        {
    
    
            if (abs(zhengGui[i][m]) > max.value) {
    
    
                max.value = abs(zhengGui[i][m]);
                max.row = i;
                max.col = m; //记录主元素列坐标
            }
        }
        if (max.row != m || max.col != m) {
    
    
            for (int i = m; i <= n + 1; i++) {
    
    
                swap(zhengGui[m][i], zhengGui[max.row][i]);
            }//行变换
        }
        for (int j = m + 1; j <= n; j++) {
    
    
            //消元
            temp = zhengGui[j][m] / zhengGui[m][m];
            for (int k = m; k <= n + 1; k++)
                zhengGui[j][k] -= zhengGui[m][k] * temp;
        }
    }
}
void Gauss(int n) {
    
    
    SelectMainE(n);
    //回代求解
    for (int i = n; i >= 1; i--) {
    
    //回代求解
        for (int j = i + 1; j <= n; j++)
            zhengGui[i][n + 1] -= zhengGui[i][j] * zhengGui[j][n + 1];
        zhengGui[i][n + 1] /= zhengGui[i][i];
    }
}
void GaussCol(int n) {
    
    
    printGuass(zhengGui, n);
    cout << endl;
    Gauss(n);
    for (int i = 1; i <= n; i++) {
    
    
        cout << "a" << i << "=" << zhengGui[i][n + 1] << endl;
    }
}
void getZhengGui(int m,int n) {
    
    
    //n为拟合多项式最高次数
    //m为数据个数
    zhengGui[1][1] = m + 1;
    for (int i = 1; i <= 2 * n; i++) {
    
    
        for (int j = 1; j <= m; j++) {
    
    
            tempx[i] += pow(x[j], i);
        }
    }
    for (int i = 1; i <= n + 1; i++) {
    
    
        for (int j = 1; j <= m; j++) {
    
    
            if (i == 1) {
    
    
                tempy[i] += y[j];
            }
            else {
    
    
                tempy[i] += y[j] * pow(x[j],i - 1);
            }
        }
    }
    for (int i = 2; i <= n + 1; i++) {
    
    
        //构造正规方程组的第一列,从第2行到第n+1行
        zhengGui[i][1] = tempx[i - 1];
    }
    int count = 1;
    for (int i = 2; i <= n + 1; i++) {
    
    
        //构造正规方程组的第2列到第n+1列
        //外循环控制列数,内循环控制行数
        
        for (int j = 1; j <= n + 1; j++) {
    
    
            zhengGui[j][i] = tempx[count];
            count++;
        }
        count -= n;
    }
    for (int i = 1; i <= n + 1; i++) {
    
    
        //构造第n+2列保存xi^n*yi
        zhengGui[i][n + 2] = tempy[i]; 
    }
}
void disp(int n) {
    
    
    cout << "\n拟合函数为:";
    cout << "f(x)=";
    printf("%.3lf",zhengGui[1][n + 1]);
    for (int i = 2; i <= n; i++) {
    
    
        printf("+%.3lf*",zhengGui[i][n + 1]);
        cout<< "x^" << i - 1;
    }
}
//计算平方误差
double niHeFunction(double x0,int n,int m) {
    
    
    //n表示矩阵中保存结果的最后一列
    //m为数据个数
    double sum = 0;
    sum += zhengGui[1][n + 1];
    for (int j = 2; j <= n; j++) {
    
    
        sum += pow(x0,j-1) * zhengGui[j][n + 1];
    }
    return sum;
}
void I(int m,int n) {
    
    
    //m为数据个数
    //n  拟合次数
    double sum = 0;
    for (int i = 1; i <= m; i++) {
    
    
        sum += pow(y[i] - niHeFunction(x[i], n, m),2);
    }
    cout << "\n平方误差为:" << sum;
}
void reset() {
    
    
    for (int i = 0; i < 8; i++) {
    
    
        for (int j = 0; j < 9; j++) {
    
    
            zhengGui[i][j] = 0;
            tempy[j] = 0;
        }
    }
    for (int i = 0; i < 15; i++) {
    
    
        tempx[i] = 0;
    }
}
void LeastSquares() {
    
    
    cout << "请输入需要拟合的数据的个数:";
    int m = 0;
    cin >> m;
    cout << "\n请输入xi:";
    for (int i = 1; i <= m; i++) {
    
    
        cin >> x[i];
    }
    cout << "\n请输入yi:";
    for (int i = 1; i <= m; i++) {
    
    
        cin >> y[i];
    }
    int cishu = 0;
    for (int i = 1; i <= m; i++) {
    
    
        cishu = i;
        getZhengGui(m, cishu);
        cout << "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
        cout << "\n当前拟合函数的最高次数为:" << cishu << endl;
        //求解正规方程组
        cout << "\n正规方程组为:" << endl;
        GaussCol(cishu+1);
        disp(cishu + 1);
        I(m,cishu+1);
        cout << "\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
        reset();
    }
    
}
int main() {
    
    
    LeastSquares();
    return 0;
}

operation result

The program will use the least squares method to fit the input data, print the fitting function with the highest order of 1-6 times and print out the normal matrix each time (the method to solve the normal matrix is ​​the Gaussian column principal elimination method), and Perform error analysis on each fitting result, and print out the squared distance. For correctness, use matlab to plot the given 6 fitting functions as follows:
insert image description here

The input data at this time is:

xi   0     0.5      0.6       0.7      0.8       0.9      1.0
yi   1     1.75     1.96      2.19     2.44      2.71     3.00   

insert image description here

Guess you like

Origin blog.csdn.net/qq_32577169/article/details/105766028