矩阵简介

前言

最近做算法相关的工作时,写了一些线性回归的代码,其中用了比较多的矩阵计算,由于已经毕业好多年,大学线性代数学的又不怎么样,所以本篇文章就回顾一下矩阵相关的知识。

正文

什么是矩阵,矩阵的本质就是一张数表,可以看成一种表示线性变换的工具

矩阵是什么样子的

矩阵是一个由多个数字组合起来的方阵,比如下面这个样子:
1 2 3 4 5 6 7 8 9 \left \\begin{matrix} 1 \& 2 \& 3 \\\\ 4 \& 5 \& 6 \\\\ 7 \& 8 \& 9 \\end{matrix} \\right ⎣ ⎡147258369⎦ ⎤

这里我们看出基本特征:

  1. "矩"的意思就是矩形,由数字组成的矩形;
  2. "阵"的意思整齐,这些数字排列起来非常整齐;
  3. 矩阵中,横向的数字是行,竖向的数字是列;
  4. 矩阵中,通过"第几行、第几列"这种简单的方式来确定某个数字的具体位置。

在上面的矩阵中,它是一个3x3的矩阵,数字8在第三行第二列,这里注意在矩阵的描述中,行和列都是从1开始算起,而不是编程中习惯地从0算起。知道了矩阵长这个样子后,有个疑问,把数字弄成这个样子有什么用?

矩阵的由来

数学之所以越来越复杂,有一个关键点是在于代数的发明 ,也就是用x这样的未知数来代替计算。比如有个小学问题:小明在市场买一些鸭子和小狗,鸭子3块钱一只,小狗7块钱一只,一共花了59块钱;小明又数了一下,鸭子和小狗一共44条腿,问小明买了多少只鸭子和多少只小狗?

这种问题我们用代数就非常容易解决,设鸭子的数量为x,小狗的数量为y,所以可以列出下面方程:

ini 复制代码
3x + 7y = 59
2x + 4y = 44

一般人看到这里就不会继续再思考了,因为问题已经解决了。但是数学家看到上面的二元一次方程的时候,会联想到一元一次方程,我们列个一元方程:

ini 复制代码
2x = 10

这时会想,有没有什么办法,可以把二元一次方程表示为和一元一次方程一样简单呢?然后解起来也非常方便呢?这个就是矩阵的雏形。

数学家发现,这个二元一次方程可以分为3个部分:

  • 第一部分,就是代数x、y左边的系数
  • 第二部分,是代数x、y本身
  • 第三部分,是等号右边的数字。

然后一元一次方程也是3个部分:

  • 第一部分,代数x左边的系数;
  • 第二部分,代数x本身;
  • 第三部分,是等号右边的数字

这时我们就可以把第一部分按照方程原先的顺序提取出来,然后是代数部分,他们是上下组合的,再加上最后一部分,所以科学家类比一元一次方程,把这3个部分给组合起来就得到:
3 7 2 4 x y = 59 44 \left \\begin{matrix} 3 \& 7 \\\\ 2 \& 4 \\\\ \\end{matrix} \\right \left \\begin{matrix} x \\\\ y \\\\ \\end{matrix} \\right = \left \\begin{matrix} 59 \\\\ 44 \\\\ \\end{matrix} \\right 3274xy=5944

这差不多就是矩阵被创造出来的大致过程了。

探究矩阵乘法

按照类似一元一次的方程是写出来了,但是怎么计算呢?我们还是来观察一下刚刚创造出来的矩阵和原来的方程有什么相通的地方,这是矩阵:
3 7 2 4 x y = 59 44 \left \\begin{matrix} 3 \& 7 \\\\ 2 \& 4 \\\\ \\end{matrix} \\right \left \\begin{matrix} x \\\\ y \\\\ \\end{matrix} \\right = \left \\begin{matrix} 59 \\\\ 44 \\\\ \\end{matrix} \\right 3274xy=5944

这是方程:
3 x + 7 y = 59 2 x + 4 y = 44 3x + 7y = 59 \\ 2x + 4y = 44 3x+7y=592x+4y=44

这里我们可以把二元一次方程的左边代入矩阵的结果,即可得到:
3 7 2 4 x y = 3 x + 7 y 2 x + 4 y \left \\begin{matrix} 3 \& 7 \\\\ 2 \& 4 \\\\ \\end{matrix} \\right \left \\begin{matrix} x \\\\ y \\\\ \\end{matrix} \\right = \left \\begin{matrix} 3x + 7y \\\\ 2x + 4y \\\\ \\end{matrix} \\right 3274xy=3x+7y2x+4y

所以这里的乘法规则就很容易看出来了。第一个矩阵的第一行和第二个矩阵的第一列数字分别相乘相加,就得到了结果的第一行的值第一个矩阵的第二行和第二个矩阵的第一列数字分别相乘相加,就得到了第二行的值。

这里我们就可以总结出2个关于矩阵相乘的规律:

  1. 第一个矩阵的列数必须和第二个矩阵的行数相等 ,才可以相乘。即只有mxn的矩阵可以和nxl的矩阵相乘,最后得到一个mxl的矩阵。

  2. 矩阵相乘不满足交换律 。这里理解起来非常容易,比如矩阵A是4x2的矩阵,矩阵B是2x3的矩阵,AxB满足上面要求,但是BxA就不可以了。

这里给出一个矩阵乘法的公式:
a 11 a 12 a 21 a 22 a 31 a 32 × b 11 b 12 b 13 b 21 b 22 b 23 = a 11 b 11 + a 12 b 21 a 11 b 12 + a 12 b 22 a 11 b 13 + a 12 b 23 a 21 b 11 + a 22 b 21 a 21 b 12 + a 22 b 22 a 21 b 13 + a 22 b 23 a 31 b 11 + a 32 b 21 a 31 b 12 + a 32 b 22 a 31 b 13 + a 32 b 23 \left \\begin{matrix} a_{11} \& a_{12} \\\\ a_{21} \& a_{22} \\\\ a_{31} \& a_{32} \\end{matrix} \\right × \left \\begin{matrix} b_{11} \& b_{12} \& b_{13}\\\\ b_{21} \& b_{22} \& b_{23} \\\\ \\end{matrix} \\right = \\ \left \\begin{matrix} a_{11}b_{11} + a_{12}b_{21} \& a_{11}b_{12}+a_{12}b_{22} \& a_{11}b_{13}+a_{12}b_{23} \\\\ a_{21}b_{11}+a_{22}b_{21} \& a_{21}b_{12}+a_{22}b_{22} \& a_{21}b_{13}+a_{22}b_{23} \\\\ a_{31}b_{11}+a_{32}b_{21} \& a_{31}b_{12}+a_{32}b_{22} \& a_{31}b_{13}+a_{32}b_{23} \\end{matrix} \\right ⎣ ⎡a11a21a31a12a22a32⎦ ⎤×b11b21b12b22b13b23=⎣ ⎡a11b11+a12b21a21b11+a22b21a31b11+a32b21a11b12+a12b22a21b12+a22b22a31b12+a32b22a11b13+a12b23a21b13+a22b23a31b13+a32b23⎦ ⎤

单位矩阵

在一元一次方程中,有个特殊的系数是1,数字1有个特点:就是和任何数相乘都不会改变他们的值 ,相似的矩阵中有没有这个"1"呢,和其他矩阵相乘不会改变其他矩阵呢?经过研究是有这种矩阵的,这种矩阵叫做单位矩阵,那单位矩阵长什么样子呢?我们可以简单推导出来,还是使用上面的例子:
3 7 2 4 x y = 3 x + 7 y 2 x + 4 y \left \\begin{matrix} 3 \& 7 \\\\ 2 \& 4 \\\\ \\end{matrix} \\right \left \\begin{matrix} x \\\\ y \\\\ \\end{matrix} \\right = \left \\begin{matrix} 3x + 7y \\\\ 2x + 4y \\\\ \\end{matrix} \\right 3274xy=3x+7y2x+4y

这里我们如何让等式右边还等于 x y \left \\begin{matrix} x \\\\ y \\\\ \\end{matrix} \\right xy呢?非常简单,我们把3改成1,7改成0,2改成0,4改成1,即变成了 1 0 0 1 \left \\begin{matrix} 1 \& 0 \\\\ 0 \& 1 \\\\ \\end{matrix} \\right 1001了就可以,这个矩阵就是一个单位矩阵。

经过研究,所有单位矩阵都有如下2个特点:

  1. 是一个正方形矩阵

  2. 除了对角线上的数字是1之外,剩下的数字都是0,单位矩阵用大写的粗体I来表示

矩阵的转置

矩阵的转置是一种操作,它将矩阵的行和列互换位置得到一个新的矩阵 。假设有一个mxn的矩阵 A A A,其转置矩阵记作 A T A^T AT,即将矩阵 A A A的第 i i i行变成 A T A^T AT的第 i i i列,将矩阵 A A A的第 j j j列变成矩阵 A T A^T AT的第 j j j行。

具体来说,如果 A = a i j A=a_{ij} A=aij是一个mxn的矩阵,则其转置矩阵 A T = b i j A^T=b_{ij} AT=bij是一个nxm的矩阵,其中 b i j = a j i b_{ij}=a_{ji} bij=aji,即矩阵 A A A的第 i i i行第 j j j列元素变成了转置矩阵 A T A^T AT的第 j j j行第 i i i列元素。

比如现在有矩阵:
A = 1 2 3 4 5 6 A=\left \\begin{matrix} 1 \& 2 \& 3 \\\\ 4 \& 5 \& 6 \\\\ \\end{matrix} \\right A=142536

那么其转置矩阵为:
A T = 1 4 2 5 3 6 A^T =\left \\begin{matrix} 1 \& 4 \\\\ 2 \& 5 \\\\ 3 \& 6 \\\\ \\end{matrix} \\right AT=⎣ ⎡123456⎦ ⎤

矩阵转置有如下几条性质:

  • ( A T ) T (A^T)^T (AT)T = A A A,即转置的转置等于原矩阵。
  • ( A + B ) T (A+B)^T (A+B)T= A T + B T A^T+B^T AT+BT,即矩阵相加后再转置等于分别转置后再相加。
  • ( k A ) T = k ( A T ) (kA)^T=k(A^T) (kA)T=k(AT),其中k为常数。
  • ( A B ) T = B T A T (AB)^T=B^TA^T (AB)T=BTAT,即2个矩阵相乘后转置等于分别转置再相乘(乘法的顺序颠倒)。

初等行变换

接下来我们在介绍逆矩阵相关知识点前,我们来看一个基本概念,叫做初等行变换

在求解线性方程组时,可以对方程组进行下列同解变形:

  • 交互2个方程的位置;
  • 用一非零数乘以某一个方程;
  • 把某个方程乘以一个常数加到另一个方程上。

比如有线性方程组:

ini 复制代码
7x + 8y + 11z = -3;     (1)
5x + y - 3z = -4;       (2)
x + 2y + 3z = 1;        (3)

将方程式(1)与方程式(3)进行交换:

ini 复制代码
x + 2y + 3z = 1;        (1)
5x + y - 3z = -4;       (2)
7x + 8y + 11z = -3;     (3)

将方程式(1)x(-5)加到方程式(2)上,将方程式(1)x(-7)加到方程式(3)上,得到如下:

ini 复制代码
x + 2y + 3z = 1;        (1)
-9y - 18z = -9;         (2)
-6y - 10z = -10;        (3)

将方程式(2)x(-1/9),将方程式(3)x(-1/2),得到如下:

ini 复制代码
x + 2y + 3z = 1;        (1)
    y  + 2z = 1;        (2)
    3y + 5z = 5;        (3)

再将方程式(2)x(-3)加到方程式(3)上,得到如下:

ini 复制代码
x + 2y + 3z = 1;        (1)
    y  + 2z = 1;        (2)
         -z = 2;        (3)

再将方程式(3)x(3)加到方程式(1),将方程式(3)x(2)加到方程式(2),得到如下:

ini 复制代码
x + 2y      = 7;        (1)
    y       = 5;        (2)
         -z = 2;        (3)

最后将方程式(2)x(-2)加到方程式(1),将方程式(3)x(-1),就可以得到方程组的解:

ini 复制代码
x           = -3;       (1)
    y       =  5;       (2)
         z  = -2;       (3)

上面流程就是我们使用消元法 求解方程组的过程,最后算出值。而我们知道矩阵的本质就是多元方程组的一种简写,所以这里类似可以给出矩阵的初等行变换定义:

  • 互换矩阵的第 i , j i,j i,j俩行,记作 r i ↔ r j r_i \leftrightarrow r_j ri↔rj,简称换行
  • 将矩阵第 i i i行各元素乘以非零常数 k k k,记作 k r i kr_i kri,简称为数乘
  • 将矩阵第 j j j行各元素数乘 k k k后加到第 i i i行的对应元素,记作 r i + k r j r_i+kr_j ri+krj,简称为倍加;

这样上面的方程组

ini 复制代码
7x + 8y + 11z = -3;     (1)
5x + y - 3z = -4;       (2)
x + 2y + 3z = 1;        (3)

我们使用曾广矩阵来表示即为:
7 8 11 − 3 5 1 − 3 − 4 1 2 3 1 \left \\begin{matrix} 7 \& 8 \& 11 \&-3 \\\\ 5 \& 1 \& -3 \& -4\\\\ 1 \& 2\& 3 \& 1\\\\ \\end{matrix} \\right ⎣ ⎡75181211−33−3−41⎦ ⎤

而把消元法的步骤对应到矩阵上来,最后得到的矩阵是:
1 0 0 − 3 0 1 0 5 0 0 1 − 2 \left \\begin{matrix} 1 \& 0 \& 0 \&-3 \\\\ 0 \& 1 \& 0 \& 5\\\\ 0 \& 0\& 1 \& -2\\\\ \\end{matrix} \\right ⎣ ⎡100010001−35−2⎦ ⎤

可以看到最终的矩阵中,左边是一个单位矩阵右边就是我们要求解的未知数的值

矩阵的逆矩阵

逆矩阵的概念和和单位矩阵相关,就比如整数5 * 1/5 = 1这种情况类似,假如有单位矩阵,我们记为 I I I,对于矩阵 A A A,如果存在 A − 1 A^{-1} A−1,使得 A A A X A − 1 A^{-1} A−1= A − 1 A^{-1} A−1X A A A= I I I,那么就称 A − 1 A^{-1} A−1为矩阵 A A A的逆矩阵

从定义上来看,逆矩阵就类似于数字的倒数,从一元一次方程来看确实如此,这里的单位矩阵I就类似于1。明确了逆矩阵的定义,我们就需要知道如何求解逆矩阵,这里我们使用初等行变换的方式来求解逆矩阵。

我们直接来说思路:假设我们需要求 A A A的逆矩阵,我们可以对矩阵 A A A进行连续的初等行变化的操作,直到将矩阵A转行为单位矩阵 I I I 。与这些初等行变化操作同步进行的是一个对同阶单位矩阵 I I I进行初等行变换操作 ,当矩阵 A A A通过不断变化为单位矩阵后,这时 I I I的操作将会把I变成矩阵 A A A的逆矩阵

通过前面的初等矩阵变化操作,我们可以预测这个操作非常复杂,我们也来看个例子,最开始有2个矩阵,一个是待求解其逆的矩阵,一个是单位矩阵:
A = 2 4 6 4 3 1 3 6 8 I = 1 0 0 0 1 0 0 0 1 A= \left \\begin{matrix} 2 \& 4 \& 6 \\\\ 4 \& 3 \& 1 \\\\ 3 \& 6 \& 8 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 1 \& 0 \& 0 \\\\ 0 \& 1 \& 0 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right A=⎣ ⎡243436618⎦ ⎤I=⎣ ⎡100010001⎦ ⎤

进行 r 1 ∗ 1 / 2 r_1 * 1/2 r1∗1/2:
A = 1 2 3 4 3 1 3 6 8 I = 1 / 2 0 0 0 1 0 0 0 1 A= \left \\begin{matrix} 1 \& 2 \& 3 \\\\ 4 \& 3 \& 1 \\\\ 3 \& 6 \& 8 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 1/2 \& 0 \& 0 \\\\ 0 \& 1 \& 0 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right A=⎣ ⎡143236318⎦ ⎤I=⎣ ⎡1/200010001⎦ ⎤

进行 r 2 + − 4 ∗ r 1 r_2 + -4 * r_1 r2+−4∗r1和 r 3 + − 3 ∗ r 1 r_3 + -3*r_1 r3+−3∗r1:
A = 1 2 3 0 − 5 − 11 0 0 − 1 I = 1 / 2 0 0 − 2 1 0 − 3 / 2 0 1 A= \left \\begin{matrix} 1 \& 2 \& 3 \\\\ 0 \& -5 \& -11 \\\\ 0 \& 0 \& -1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 1/2 \& 0 \& 0 \\\\ -2 \& 1 \& 0 \\\\ -3/2 \& 0 \& 1 \\\\ \\end{matrix} \\right A=⎣ ⎡1002−503−11−1⎦ ⎤I=⎣ ⎡1/2−2−3/2010001⎦ ⎤

进行 r 3 ∗ − 1 r_3 * -1 r3∗−1:
A = 1 2 3 0 − 5 − 11 0 0 1 I = 1 / 2 0 0 − 2 1 0 3 / 2 0 − 1 A= \left \\begin{matrix} 1 \& 2 \& 3 \\\\ 0 \& -5 \& -11 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 1/2 \& 0 \& 0 \\\\ -2 \& 1 \& 0 \\\\ 3/2 \& 0 \& -1 \\\\ \\end{matrix} \\right A=⎣ ⎡1002−503−111⎦ ⎤I=⎣ ⎡1/2−23/201000−1⎦ ⎤

进行 r 2 ∗ 2 / 5 + r 1 r_2 * 2/5 + r_1 r2∗2/5+r1:
A = 1 0 − 7 / 5 0 − 5 − 11 0 0 1 I = − 3 / 10 2 / 5 0 − 2 1 0 3 / 2 0 − 1 A= \left \\begin{matrix} 1 \& 0 \& -7/5 \\\\ 0 \& -5 \& -11 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} -3/10 \& 2/5 \& 0 \\\\ -2 \& 1 \& 0 \\\\ 3/2 \& 0 \& -1 \\\\ \\end{matrix} \\right A=⎣ ⎡1000−50−7/5−111⎦ ⎤I=⎣ ⎡−3/10−23/22/51000−1⎦ ⎤

进行 r 3 ∗ 7 / 5 + r 1 r_3*7/5 + r_1 r3∗7/5+r1:
A = 1 0 0 0 − 5 − 11 0 0 1 I = 9 / 5 2 / 5 − 7 / 5 − 2 1 0 3 / 2 0 − 1 A= \left \\begin{matrix} 1 \& 0 \& 0 \\\\ 0 \& -5 \& -11 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 9/5 \& 2/5 \& -7/5 \\\\ -2 \& 1 \& 0 \\\\ 3/2 \& 0 \& -1 \\\\ \\end{matrix} \\right A=⎣ ⎡1000−500−111⎦ ⎤I=⎣ ⎡9/5−23/22/510−7/50−1⎦ ⎤

进行 r 2 ∗ − 1 / 5 r_2*-1/5 r2∗−1/5:
A = 1 0 0 0 1 11 / 5 0 0 1 I = 9 / 5 2 / 5 − 7 / 5 2 / 5 − 1 / 5 0 3 / 2 0 − 1 A= \left \\begin{matrix} 1 \& 0 \& 0 \\\\ 0 \& 1 \& 11/5 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 9/5 \& 2/5 \& -7/5 \\\\ 2/5 \& -1/5 \& 0 \\\\ 3/2 \& 0 \& -1 \\\\ \\end{matrix} \\right A=⎣ ⎡100010011/51⎦ ⎤I=⎣ ⎡9/52/53/22/5−1/50−7/50−1⎦ ⎤

进行 r 3 ∗ − 11 / 5 + r 2 r_3*-11/5 + r2 r3∗−11/5+r2:
A = 1 0 0 0 1 0 0 0 1 I = 9 / 5 2 / 5 − 7 / 5 − 29 / 10 − 1 / 5 11 / 5 3 / 2 0 − 1 A= \left \\begin{matrix} 1 \& 0 \& 0 \\\\ 0 \& 1 \& 0 \\\\ 0 \& 0 \& 1 \\\\ \\end{matrix} \\right I= \left \\begin{matrix} 9/5 \& 2/5 \& -7/5 \\\\ -29/10 \& -1/5 \& 11/5 \\\\ 3/2 \& 0 \& -1 \\\\ \\end{matrix} \\right A=⎣ ⎡100010001⎦ ⎤I=⎣ ⎡9/5−29/103/22/5−1/50−7/511/5−1⎦ ⎤

这时矩阵 A A A变成了单位矩阵,原单位矩阵就是逆矩阵 A − 1 A^{-1} A−1。

这个化为单位矩阵的过程并不唯一,基本思路就是先将第一列除第一行外的元素化为0,再将第二列除第二行外的元素化为0,然后操作第三列,这个过程非常复杂,容易出错,我们使用代码来验证一下:

C++ 复制代码
    Eigen::MatrixXf A(3,3);
    A << 2,4,6,
            4,3,1,
            3,6,8;
    std::cout << "------ A ------" << std::endl << A << std::endl;
    std::cout << "------ A.inverse ------" << std::endl << A.inverse() << std::endl;
    
    //运行结果
    ------ A ------
2 4 6
4 3 1
3 6 8
------ A.inverse ------
         1.8          0.4         -1.4
        -2.9         -0.2          2.2
         1.5 2.23517e-008           -1

可以发现结果是正确的,为什么这里的0会变成一个非常小的数,是因为矩阵的数据类型是float类型。

总结

本篇文章主要简单介绍了矩阵相关概念,以及最后使用Eigen库来验证我们的推导,这些是算法的基础,必须要理解。

相关推荐
想吃火锅100510 小时前
【leetcode】88.合并两个有序数组js
算法
один but you11 小时前
constexpr函数
c++
生成论实验室11 小时前
机器人:一个自主运动的系统
人工智能·算法·语言模型·机器人·自动驾驶·agi·安全架构
Qres82111 小时前
算法复键——树状数组
数据结构·算法
H1785350909611 小时前
SolidWorks第四部分_直接实体建模特征9_替换面原理
线性代数·算法·机器学习·3d建模·solidworks
凡人叶枫11 小时前
Effective C++ 条款41:了解隐式接口和编译期多态
java·开发语言·c++·effective c++
不会就选b11 小时前
算法日常・每日刷题--<二分查找>3
算法
凡人叶枫11 小时前
Effective C++ 条款42:了解 typename 的双重意义
java·linux·服务器·c++
小胖xiaopangss11 小时前
BRpc使用
c++·rpc
绿算技术12 小时前
Mooncake 与绿算ForinnBase GroundPool如何联手打破推理僵局?
科技·算法·架构