矩阵运算(一)最小二乘法

最小二乘法

  • 前言
  • 最小二乘法拟合一元多项式的简单推导
  • 进一步的思考
  • CPP开发者封装最小二乘法
  • QR分解
    • Matlab中使用QR分解
    • Python numpy中使用
  • 参考文献
  • 作者说

前言

  最小二乘法在函数拟合的过程中广为应用,不少读者使用笔者早期写的矩阵运算库,以求逆的方式得到拟合系数,这种算法虽然简单,但并不健壮;而使用QR分解(induced QR)得到的最小二乘法的结果,不论是在数据精度上的保证,还是算法时间复杂度上都得到了质的飞跃。

最小二乘法拟合一元多项式的简单推导

  设自变量为 x x x,因变量为 y y y,欲求一元二次多项式 y = a n x n + a n − 1 x n − 1 + . . . . . . + a 0 y=a_{n}x^{n}+a_{n-1}x^{n-1}+......+a_{0} y=anxn+an1xn1+......+a0
即求系数 a n , a n − 1 , . . . . . . , a 0 a_{n},a_{n-1},......,a_{0} an,an1,......,a0
  将 m m m x x x构建为矩阵 A A A
[ 1 x 1 . . . x 1 n 1 x 2 . . . x 2 n 1 x 3 . . . x 3 n . . . 1 x m . . . x m n ] \begin{bmatrix} 1 & x_{1} &... &x_{1}^{n}\\ 1 &x_{2} & ... &x_{2}^{n} \\ 1 & x_{3}&... & x_{3}^{n}\\ ...\\ 1 & x_{m}&... & x_{m}^{n} \end{bmatrix} 111...1x1x2x3xm............x1nx2nx3nxmn
  可得方程 A b = Y Ab = Y Ab=Y
  其中 b = [ a 0 , a 1 , . . . , a n ] T b = [a_{0},a_{1},...,a_{n}]^{T} b=[a0,a1,...,an]T
   Y = [ y 1 , y 2 , . . . , y m ] T Y=[y_{1},y_{2},...,y_{m}]^{T} Y=[y1,y2,...,ym]T
  在 m = n m=n m=n的情况下有 b = A − 1 Y b = A^{-1}Y b=A1Y
  在 m ≠ n m\neq n m=n的情况下有 A T A b = A T Y A^{T}Ab = A^{T}Y ATAb=ATY
  令 T = A T A T =A^{T}A T=ATA
  则 b = T − 1 A T Y b = T^{-1}A^{T}Y b=T1ATY

进一步的思考

  矩阵求逆的时间复杂度较大为 O ( m 3 ) O(m^{3}) O(m3),因此算法工程师在实现最小二乘法的过程中会调用QR分解,QR分解的实现不算复杂,但可能要耗费编程者的很多心思,笔者在这里建议读者调用Eigen库以实现这一结果。

CPP开发者封装最小二乘法

  使用CPP封装最小二乘法的时候,笔者建议使用Eigen库

//张九韶算法
inline double polyeval(Eigen::VectorXd coeffs, double x) {
  double result = 0.0;
  for(int i= coeffs.size()-1;i>0;i--){
  		result+=coeffs[i];
  		result*=x;
  }
  result+=coeffs[0];
  return result;
}
//系数拟合
Eigen::VectorXd polyfit(Eigen::VectorXd xvals, Eigen::VectorXd yvals, int order) {
  assert(xvals.size() == yvals.size());
  assert(order >= 1 && order <= xvals.size() - 1);
  Eigen::MatrixXd A(xvals.size(), order + 1);
  for (int i = 0; i < xvals.size(); i++) {
    A(i, 0) = 1.0;
  }
  for (int j = 0; j < xvals.size(); j++) {
    for (int i = 0; i < order; i++) {
      A(j, i + 1) = A(j, i) * xvals(j);
    }
  }
  auto Q = A.householderQr();
  auto result = Q.solve(yvals);
  return result;
}

QR分解

Matlab中使用QR分解

[Q,R]=qr(A)

Python numpy中使用

import numpy as np
q,r = np.linalg.qr(A)

参考文献

[1] 矩阵论 戴华

作者说

  笔者初学C++时写过一篇矩阵运算的文章,近期这篇文章反响不错,自认为当时那篇文章太过粗糙,笔者将持续推出矩阵运算这一系列的文章,希望读者能够喜欢。当然,如果你对内容有疑惑,欢迎你联系我的邮箱[email protected],如果你想支持我的创造,欢迎打赏,我的支付宝账号是[email protected]

你可能感兴趣的:(矩阵论)