一,原理
二,根据原理得到的 python 源码。
import matplotlib.pyplot as plt import math import numpy import random fig = plt.figure() ax = fig.add_subplot(111) #阶数为9阶 order=9 #生成曲线上的各个点 x = numpy.arange(-1,1,0.02) y = [((a*a-1)*(a*a-1)*(a*a-1)+0.5)*numpy.sin(a*2) for a in x] #ax.plot(x,y,color='r',linestyle='-',marker='') #,label="(a*a-1)*(a*a-1)*(a*a-1)+0.5" #生成的曲线上的各个点偏移一下,并放入到xa,ya中去 i=0 xa=[] ya=[] for xx in x: yy=y[i] d=float(random.randint(70,130))/100 #ax.plot([xx*d],[yy*d],color='m',linestyle='',marker='.') i+=1 xa.append(xx*d) ya.append(yy*d) '''''for i in range(0,5): xx=float(random.randint(-100,100))/100 yy=float(random.randint(-60,60))/100 xa.append(xx) ya.append(yy)''' ax.plot(xa,ya,color='m',linestyle='',marker='.') #plt.show() #print(ax) #进行曲线拟合 matA=[] for i in range(0,order+1): matA1=[] for j in range(0,order+1): tx=0.0 for k in range(0,len(xa)): dx=1.0 for l in range(0,j+i): dx=dx*xa[k] tx+=dx matA1.append(tx) matA.append(matA1) #print(len(xa)) #print(matA[0][0]) matA=numpy.array(matA) matB=[] for i in range(0,order+1): ty=0.0 for k in range(0,len(xa)): dy=1.0 for l in range(0,i): dy=dy*xa[k] ty+=ya[k]*dy matB.append(ty) matB=numpy.array(matB) matAA=numpy.linalg.solve(matA,matB) print (matAA) print (matA) print (matB) #画出拟合后的曲线 #print(matAA) xxa= numpy.arange(-1,1.06,0.01) yya=[] for i in range(0,len(xxa)): yy=0.0 for j in range(0,order+1): dy=1.0 for k in range(0,j): dy*=xxa[i] dy*=matAA[j] yy+=dy yya.append(yy) ax.plot(xxa,yya,color='g',linestyle='-',marker='') ax.legend("aw") plt.show()
python的结果
三,下面是c++实现。
c++第一部分:这里用了一个自己写的Matrix 类,作为头文件Matrix.h
#include<iostream> #include <fstream> // std::ifstream #include <stdlib.h> #include <cmath> using namespace std; class Matrix { private: unsigned row, col, size; double *pmm;//数组指针 public: Matrix(unsigned r, unsigned c) :row(r), col(c)//非方阵构造 { size = r*c; if (size>0) { pmm = new double[size]; for (unsigned j = 0; j<size; j++) //init { pmm[j] = 0.0; } } else pmm = NULL; }; Matrix(unsigned n) :row(n), col(n)//方阵构造 { size = n*n; if (size>0) { pmm = new double[size]; for (unsigned j = 0; j<size; j++) //init { pmm[j] = 0.0; } } else pmm = NULL; }; Matrix(const Matrix &rhs)//拷贝构造 { row = rhs.row; col = rhs.col; size = rhs.size; pmm = new double[size]; for (unsigned i = 0; i<size; i++) pmm[i] = rhs.pmm[i]; } ~Matrix()//析构 { if (pmm != NULL) { delete[]pmm; pmm = NULL; } } Matrix &operator=(const Matrix&); //如果类成员有指针必须重写赋值运算符,必须是成员 friend istream &operator>>(istream&, Matrix&); friend ofstream &operator<<(ofstream &out, Matrix &obj); friend ostream &operator<<(ostream&, Matrix&); friend Matrix operator+(const Matrix&, const Matrix&); friend Matrix operator*(const Matrix&, const Matrix&); Matrix cov(_In_opt_ bool flag = true); //协方差阵 或者样本方差 double det(); //行列式 Matrix solveAb(Matrix &obj); // b是行向量或者列向量 Matrix diag(); //返回对角线元素 //Matrix asigndiag(); //对角线元素 Matrix T()const; //转置 void sort(bool);//true为从小到大 Matrix adjoint(); Matrix inverse(); void QR(_Out_ Matrix&, _Out_ Matrix&)const; Matrix eig_val(_In_opt_ unsigned _iters = 1000); Matrix eig_vect(_In_opt_ unsigned _iters = 1000); unsigned Row()const{ return row; } unsigned Col()const{ return col; } double norm1();//1范数 double norm2();//2范数 double*operator[](int i){ return pmm + i*col; }//注意this加括号, (*this)[i][j] void zeromean(_In_opt_ bool flag = true);//默认参数为true计算列 void normalize(_In_opt_ bool flag = true);//默认参数为true计算列 Matrix exponent(double x);//每个元素x次幂 Matrix eye();//对角阵 void maxlimit(double max,double set=0);//对角阵 }; //友元仅仅是指定了访问权限,不是一般意义的函数声明,最好在类外再进行一次函数声明。 //istream &operator>>(istream &is, Matrix &obj); //ostream &operator<<(ostream &is, Matrix &obj); //对称性运算符,如算术,相等,应该是普通非成员函数。 //Matrix operator*( const Matrix&,const Matrix& ); //Matrix operator+( const Matrix&,const Matrix& ); //dets递归调用 double dets(int n, double *&aa) { if (n == 1) return aa[0]; double *bb = new double[(n - 1)*(n - 1)];//创建n-1阶的代数余子式阵bb int mov = 0;//判断行是否移动 double sum = 0.0;//sum为行列式的值 for (int arow = 0; arow<n; arow++) // a的行数把矩阵a(nn)赋值到b(n-1) { for (int brow = 0; brow<n - 1; brow++)//把aa阵第一列各元素的代数余子式存到bb { mov = arow > brow ? 0 : 1; //bb中小于arow的行,同行赋值,等于的错过,大于的加一 for (int j = 0; j<n - 1; j++) //从aa的第二列赋值到第n列 { bb[brow*(n - 1) + j] = aa[(brow + mov)*n + j + 1]; } } int flag = (arow % 2 == 0 ? 1 : -1);//因为列数为0,所以行数是偶数时候,代数余子式为1. sum += flag* aa[arow*n] * dets(n - 1, bb);//aa第一列各元素与其代数余子式积的和即为行列式 } delete[]bb; return sum; } Matrix Matrix::solveAb(Matrix &obj) { Matrix ret(row, 1); if (size == 0 || obj.size == 0) { cout << "solveAb(Matrix &obj):this or obj is null" << endl; return ret; } if (row != obj.size) { cout << "solveAb(Matrix &obj):the row of two matrix is not equal!" << endl; return ret; } double *Dx = new double[row*row]; for (int i = 0; i<row; i++) { for (int j = 0; j<row; j++) { Dx[i*row + j] = pmm[i*row + j]; } } double D = dets(row, Dx); if (D == 0) { cout << "Cramer法则只能计算系数矩阵为满秩的矩阵" << endl; return ret; } for (int j = 0; j<row; j++) { for (int i = 0; i<row; i++) { for (int j = 0; j<row; j++) { Dx[i*row + j] = pmm[i*row + j]; } } for (int i = 0; i<row; i++) { Dx[i*row + j] = obj.pmm[i]; //obj赋值给第j列 } //for( int i=0;i<row;i++) //print //{ // for(int j=0; j<row;j++) // { // cout<< Dx[i*row+j]<<"\t"; // } // cout<<endl; //} ret[j][0] = dets(row, Dx) / D; } delete[]Dx; return ret; } Matrix Matrix::exponent(double x)//每个元素x次幂 { Matrix ret(row, col); double a; for (unsigned i = 0; i< row; i++) { for (unsigned j = 0; j < col; j++) { a=ret[i][j]= pow(pmm[i*col + j],x); } } return ret; } void Matrix::maxlimit(double max, double set)//每个元素x次幂 { for (unsigned i = 0; i< row; i++) { for (unsigned j = 0; j < col; j++) { pmm[i*col + j] = pmm[i*col + j]>max ? 0 : pmm[i*col + j]; } } } Matrix Matrix::eye()//对角阵 { for (unsigned i = 0; i< row; i++) { for (unsigned j = 0; j < col; j++) { if (i == j) { pmm[i*col + j] = 1.0; } } } return *this; } void Matrix::zeromean(_In_opt_ bool flag) { if (flag == true) //计算列均值 { double *mean = new double[col]; for (unsigned j = 0; j < col; j++) { mean[j] = 0.0; for (unsigned i = 0; i < row; i++) { mean[j] += pmm[i*col + j]; } mean[j] /= row; } for (unsigned j = 0; j < col; j++) { for (unsigned i = 0; i < row; i++) { pmm[i*col + j] -= mean[j]; } } delete[]mean; } else //计算行均值 { double *mean = new double[row]; for (unsigned i = 0; i< row; i++) { mean[i] = 0.0; for (unsigned j = 0; j < col; j++) { mean[i] += pmm[i*col + j]; } mean[i] /= col; } for (unsigned i = 0; i < row; i++) { for (unsigned j = 0; j < col; j++) { pmm[i*col + j] -= mean[i]; } } delete[]mean; } } void Matrix::normalize(_In_opt_ bool flag) { if (flag == true) //计算列均值 { double *mean = new double[col]; for (unsigned j = 0; j < col; j++) { mean[j] = 0.0; for (unsigned i = 0; i < row; i++) { mean[j] += pmm[i*col + j]; } mean[j] /= row; } for (unsigned j = 0; j < col; j++) { for (unsigned i = 0; i < row; i++) { pmm[i*col + j] -= mean[j]; } } ///计算标准差 for (unsigned j = 0; j < col; j++) { mean[j] = 0; for (unsigned i = 0; i < row; i++) { mean[j] += pow(pmm[i*col + j],2);//列平方和 } mean[j] = sqrt(mean[j] / row); // 开方 } for (unsigned j = 0; j < col; j++) { for (unsigned i = 0; i < row; i++) { pmm[i*col + j] /= mean[j];//列平方和 } } delete[]mean; } else //计算行均值 { double *mean = new double[row]; for (unsigned i = 0; i< row; i++) { mean[i] = 0.0; for (unsigned j = 0; j < col; j++) { mean[i] += pmm[i*col + j]; } mean[i] /= col; } for (unsigned i = 0; i < row; i++) { for (unsigned j = 0; j < col; j++) { pmm[i*col + j] -= mean[i]; } } ///计算标准差 for (unsigned i = 0; i< row; i++) { mean[i] = 0.0; for (unsigned j = 0; j < col; j++) { mean[i] += pow(pmm[i*col + j], 2);//列平方和 } mean[i] = sqrt(mean[i] / col); // 开方 } for (unsigned i = 0; i < row; i++) { for (unsigned j = 0; j < col; j++) { pmm[i*col + j] /= mean[i]; } } delete[]mean; } } double Matrix::det() { if (col == row) return dets(row, pmm); else { cout << ("行列不相等无法计算") << endl; return 0; } } ///////////////////////////////////////////////////////////////////// istream &operator>>(istream &is, Matrix &obj) { for (unsigned i = 0; i<obj.size; i++) { is >> obj.pmm[i]; } return is; } ostream &operator<<(ostream &out, Matrix &obj) { for (unsigned i = 0; i < obj.row; i++) //打印逆矩阵 { for (unsigned j = 0; j < obj.col; j++) { out << (obj[i][j]) << "\t"; } out << endl; } return out; } ofstream &operator<<(ofstream &out, Matrix &obj)//打印逆矩阵到文件 { for (unsigned i = 0; i < obj.row; i++) { for (unsigned j = 0; j < obj.col; j++) { out << (obj[i][j]) << "\t"; } out << endl; } return out; } Matrix operator+(const Matrix& lm, const Matrix& rm) { Matrix ret(lm.row, lm.col); for (unsigned i = 0; i<ret.size; i++) { ret.pmm[i] = lm.pmm[i] + rm.pmm[i]; } return ret; } Matrix operator*(const Matrix& lm, const Matrix& rm) { if (lm.size == 0 || rm.size == 0 || lm.col != rm.row) { Matrix temp(0, 0); temp.pmm = NULL; return temp; //数据不合法时候,返回空矩阵 } Matrix ret(lm.row, rm.col); for (unsigned i = 0; i<lm.row; i++) { for (unsigned j = 0; j< rm.col; j++) { for (unsigned k = 0; k< lm.col; k++)//lm.col == rm.row { ret.pmm[i*rm.col + j] += lm.pmm[i*lm.col + k] * rm.pmm[k*rm.col + j]; } } } return ret; } Matrix& Matrix::operator=(const Matrix& rhs) { if (this != &rhs) { row = rhs.row; col = rhs.col; size = rhs.size; if (pmm != NULL) delete[] pmm; pmm = new double[size]; for (unsigned i = 0; i<size; i++) { pmm[i] = rhs.pmm[i]; } } return *this; } //||matrix||_2 求A矩阵的2范数 double Matrix::norm2() { double norm = 0; for (unsigned i = 0; i < size; ++i) { norm += pmm[i] * pmm[i]; } return (double)sqrt(norm); } double Matrix::norm1() { double sum = 0; for (unsigned i = 0; i < size; ++i) { sum += abs(pmm[i]); } return sum; } void Matrix::sort(bool flag) { double tem; for (unsigned i = 0; i<size; i++) { for (unsigned j = i + 1; j<size; j++) { if (flag == true) { if (pmm[i]>pmm[j]) { tem = pmm[i]; pmm[i] = pmm[j]; pmm[j] = tem; } } else { if (pmm[i]<pmm[j]) { tem = pmm[i]; pmm[i] = pmm[j]; pmm[j] = tem; } } } } } Matrix Matrix::diag() { if (row != col) { Matrix m(0); cout << "diag():row != col" << endl; return m; } Matrix m(row); for (unsigned i = 0; i<row; i++) { m.pmm[i*row + i] = pmm[i*row + i]; } return m; } Matrix Matrix::T()const { Matrix tem(col, row); for (unsigned i = 0; i<row; i++) { for (unsigned j = 0; j<col; j++) { tem[j][i] = pmm[i*col + j];// (*this)[i][j] } } return tem; } void Matrix::QR(Matrix &Q, Matrix &R) const { //如果A不是一个二维方阵,则提示错误,函数计算结束 if (row != col) { printf("ERROE: QR() parameter A is not a square matrix!\n"); return; } const unsigned N = row; double *a = new double[N]; double *b = new double[N]; for (unsigned j = 0; j < N; ++j) //(Gram-Schmidt) 正交化方法 { for (unsigned i = 0; i < N; ++i) //第j列的数据存到a,b a[i] = b[i] = pmm[i * N + j]; for (unsigned i = 0; i<j; ++i) //第j列之前的列 { R.pmm[i * N + j] = 0; // for (unsigned m = 0; m < N; ++m) { R.pmm[i * N + j] += a[m] * Q.pmm[m *N + i]; //R[i,j]值为Q第i列与A的j列的内积 } for (unsigned m = 0; m < N; ++m) { b[m] -= R.pmm[i * N + j] * Q.pmm[m * N + i]; // } } double norm = 0; for (unsigned i = 0; i < N; ++i) { norm += b[i] * b[i]; } norm = (double)sqrt(norm); R.pmm[j*N + j] = norm; //向量b[]的2范数存到R[j,j] for (unsigned i = 0; i < N; ++i) { Q.pmm[i * N + j] = b[i] / norm; //Q 阵的第j列为单位化的b[] } } delete[]a; delete[]b; } Matrix Matrix::eig_val(_In_opt_ unsigned _iters) { if (size == 0 || row != col) { cout << "矩阵为空或者非方阵!" << endl; Matrix rets(0); return rets; } //if (det() == 0) //{ // cout << "非满秩矩阵没法用QR分解计算特征值!" << endl; // Matrix rets(0); // return rets; //} const unsigned N = row; Matrix matcopy(*this);//备份矩阵 Matrix Q(N), R(N); /*当迭代次数足够多时,A 趋于上三角矩阵,上三角矩阵的对角元就是A的全部特征值。*/ for (unsigned k = 0; k < _iters; ++k) { //cout<<"this:\n"<<*this<<endl; QR(Q, R); *this = R*Q; /* cout<<"Q:\n"<<Q<<endl; cout<<"R:\n"<<R<<endl; */ } Matrix val = diag(); *this = matcopy;//恢复原始矩阵; return val; } Matrix Matrix::eig_vect(_In_opt_ unsigned _iters) { if (size == 0 || row != col) { cout << "矩阵为空或者非方阵!" << endl; Matrix rets(0); return rets; } if (det() == 0) { cout << "非满秩矩阵没法用QR分解计算特征向量!" << endl; Matrix rets(0); return rets; } Matrix matcopy(*this);//备份矩阵 Matrix eigenValue = eig_val(_iters); Matrix ret(row); const unsigned NUM = col; double eValue; double sum, midSum, diag; Matrix copym(*this); for (unsigned count = 0; count < NUM; ++count) { //计算特征值为eValue,求解特征向量时的系数矩阵 *this = copym; eValue = eigenValue[count][count]; for (unsigned i = 0; i < col; ++i)//A-lambda*I { pmm[i * col + i] -= eValue; } //cout<<*this<<endl; //将 this为阶梯型的上三角矩阵 for (unsigned i = 0; i < row - 1; ++i) { diag = pmm[i*col + i]; //提取对角元素 for (unsigned j = i; j < col; ++j) { pmm[i*col + j] /= diag; //【i,i】元素变为1 } for (unsigned j = i + 1; j<row; ++j) { diag = pmm[j * col + i]; for (unsigned q = i; q < col; ++q)//消去第i+1行的第i个元素 { pmm[j*col + q] -= diag*pmm[i*col + q]; } } } //cout<<*this<<endl; //特征向量最后一行元素置为1 midSum = ret.pmm[(ret.row - 1) * ret.col + count] = 1; for (int m = row - 2; m >= 0; --m) { sum = 0; for (unsigned j = m + 1; j < col; ++j) { sum += pmm[m * col + j] * ret.pmm[j * ret.col + count]; } sum = -sum / pmm[m * col + m]; midSum += sum * sum; ret.pmm[m * ret.col + count] = sum; } midSum = sqrt(midSum); for (unsigned i = 0; i < ret.row; ++i) { ret.pmm[i * ret.col + count] /= midSum; //每次求出一个列向量 } } *this = matcopy;//恢复原始矩阵; return ret; } Matrix Matrix::cov(bool flag) { //row 样本数,column 变量数 if (col == 0) { Matrix m(0); return m; } double *mean = new double[col]; //均值向量 for (unsigned j = 0; j<col; j++) //init { mean[j] = 0.0; } Matrix ret(col); for (unsigned j = 0; j<col; j++) //mean { for (unsigned i = 0; i<row; i++) { mean[j] += pmm[i*col + j]; } mean[j] /= row; } unsigned i, k, j; for (i = 0; i<col; i++) //第一个变量 { for (j = i; j<col; j++) //第二个变量 { for (k = 0; k<row; k++) //计算 { ret[i][j] += (pmm[k*col + i] - mean[i])*(pmm[k*col + j] - mean[j]); } if (flag == true) { ret[i][j] /= (row-1); } else { ret[i][j] /= (row); } /*temp.Format("cov=%f,column=%d mean(%d)=%f,mean(%d)=%f",cov[i*column+j],row,i,mean[i],j,mean[j]); MessageBox(temp);*/ } } for (i = 0; i<col; i++) //补全对应面 { for (j = 0; j<i; j++) { ret[i][j] = ret[j][i]; } } return ret; } Matrix Matrix::adjoint() { //调动之前,检查时候方阵,这里默认为aa为方阵 //确定本函数是否修改传入的数据 :no //调用函数内删除内存delete []padjoint; if (row != col) { Matrix ret(0); return ret; } const int n = row; Matrix ret(row); double *bb = new double[(n - 1)*(n - 1)];//创建n-1阶的代数余子式阵bb int pi, pj, q; for (int ai = 0; ai<n; ai++) // a的行数把矩阵a(nn)赋值到b(n-1) { for (int aj = 0; aj<n; aj++) { for (int bi = 0; bi<n - 1; bi++)//把元素aa[ai][0]余子式存到bb[][] { for (int bj = 0; bj<n - 1; bj++)//把元素aa[ai][0]代数余子式存到bb[][] { if (ai>bi) //ai行的代数余子式是:小于ai的行,aa与bb阵,同行赋值 pi = 0; else pi = 1; //大于等于ai的行,取aa阵的ai+1行赋值给阵bb的bi行 if (aj>bj) //ai行的代数余子式是:小于ai的行,aa与bb阵,同行赋值 pj = 0; else pj = 1; //大于等于ai的行,取aa阵的ai+1行赋值给阵bb的bi行 bb[bi*(n - 1) + bj] = pmm[(bi + pi)*n + bj + pj]; } } if ((ai + aj) % 2 == 0) q = 1;//因为列数为0,所以行数是偶数时候,代数余子式为-1. else q = (-1); ret.pmm[ai*n + aj] = q*dets(n - 1, bb); //加符号变为代数余子式 } } delete[]bb; return ret; } Matrix Matrix::inverse() { double det_aa = det(); if (det_aa == 0) { cout << "行列式为0 ,不能计算逆矩阵。" << endl; Matrix rets(0); return rets; } Matrix adj = adjoint(); Matrix ret(row); for (unsigned i = 0; i<row; i++) //print { for (unsigned j = 0; j<col; j++) { ret.pmm[i*col + j] = adj.pmm[i*col + j] / det_aa; } } return ret; }
c++第二部分:主函数部分
#include "matrix.h" #include <math.h> #include<iostream> #include<fstream> const int N = 100; double fun(double x) { return (pow((x*x - 1), 3.0) + 0.5)*sin(x * 2); } int main() { Matrix x(1, N); Matrix y(1, N); ofstream ofs; ofs.open("pydata.txt", ofstream::out); double src = -1.0; for (int i = 0; i < N; i++) { src += 0.02; x[0][i] = src; y[0][i] = fun(src); } Matrix sx(x);//加入随机因素前的x for (int i = 0; i < N; i++) { double ran = rand() % 600 / 1000.0 + 0.7; // 0.7~1.3 倍的随机 x[0][i] = x[0][i]*ran; y[0][i] = y[0][i] * ran; } //构建矩阵 int k = 8; //次方数 Matrix xx(k + 1, k + 1); //累加矩阵k+1阶 for (size_t r = 0; r < k+1; r++) { for (size_t c = r; c < k+1; c++) { double sum = 0; for (size_t i = 0; i < N; i++) { sum += pow(x[0][i], r+c); } xx[c][r]=xx[r][c] = sum; } } cout << "xx:\n"<<xx; Matrix yy(k+1, 1); //累加 y 向量yy for (size_t r = 0; r < k + 1; r++) { double sum = 0; for (size_t i = 0; i < N; i++) { sum += pow(x[0][i], r )* y[0][i]; } yy[r][0] = sum; } cout << "yy:\n" << yy; Matrix aa= xx.solveAb(yy); // 克拉默法则求 xx*aa = yy 中的aa cout << "aa:\n" << aa << endl; Matrix py(1, 100); //预测值 py for (size_t i = 0; i < N ; i++) //对N个元素预测 { double sum = 0; for (size_t a = 0; a < k+1; a++) { sum += pow(sx[0][i], a)* aa[a][0]; } py[0][i] = sum; ofs << x[0][i] << " " << y[0][i] << " " << py[0][i]<<endl; } ofs.close(); system("pause"); }
c++第三部分: 根据c++的输出 pydata.txt 用python画图
import matplotlib.pyplot as plt import numpy fin = open("pydata.txt", "r") line = fin.readline() x=[] y=[] py=[] while line: #print(line) line=line.strip() line=line.split() x.append(float(line[0])) y.append(float(line[1])) py.append(float(line[2])) line = fin.readline() fin.close() ax = plt.subplot(111) xa= numpy.arange(-1,1,0.02) ax.plot(xa,y,color='m',linestyle='',marker='.') ax.plot(xa,py,color='g',linestyle='-',marker='') plt.show()
画图的结果