矩阵
什么是矩阵
定义: 一般的, 由$m\times n$个元素$a_{ij}$ $(i=1,2,\cdots,m;j=1,2,\cdots,n)$按确定的位置排列成的矩形阵列称为矩阵.
向量也是一种形式的矩阵, 或者说矩阵中的每行或者每列为向量.
$$
\boldsymbol{A}=\begin{bmatrix}
a_{11} & a_{12} & \cdots & a_{1n} \\
a_{21} & a_{22} & \cdots & a_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
a_{m1} & a_{m2} & \cdots & a_{mn}
\end{bmatrix}
$$
可以简写为$\boldsymbol{A}=(a_{ij})$或者$\boldsymbol{A}=(a_{ij})_{m\times n}$
如果$m=n$, 则称此矩阵为$n$阶方阵
$$
\boldsymbol{A}=\begin{bmatrix}
a_{11} & a_{12} & \cdots & a_{1n} \\
a_{21} & a_{22} & \cdots & a_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
a_{n1} & a_{n2} & \cdots & a_{nn}
\end{bmatrix}
$$
在Python中, 可以用Numpy的二维数组表示矩阵
import numpy as np
matrix_I=np.array([[1,0,0],[0,1,0],[0,0,1]])
print(matrix_I)
'''
[[1 0 0]
[0 1 0]
[0 0 1]]
'''
或者用专门的矩阵类:
import numpy as np
a=np.asmatrix("0 0 1;0 1 0;0 0 1")
print(a)
'''
[[1 0 0]
[0 1 0]
[0 0 1]]
'''
但是这两种对象是不同的, 需要注意.
单位矩阵
在三维向量中有这样一个标准基$\{ \begin{bmatrix}1\\ 0 \\ 0\end{bmatrix},\begin{bmatrix}0\\ 1 \\0\end{bmatrix} ,\begin{bmatrix}0\\0 \\1\end{bmatrix}\}$, 写成矩阵就是$\begin{bmatrix}1&0&0\\ 0&1&0 \\ 0&0&1\end{bmatrix}$, 称为单位矩阵, 用$\boldsymbol{I}$或$\boldsymbol{E}$表示.
$$
\boldsymbol{I}_n=\begin{bmatrix}
1 & 0 & \cdots & 0 \\
0 & 1 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & 1
\end{bmatrix}
$$
单位矩阵是方阵.
零矩阵
所有元素都为零的矩阵称为零矩阵.
$$
\boldsymbol{O}_{mn}=\begin{bmatrix}
0 & 0 & \cdots & 0 \\
0 & 0 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & 0
\end{bmatrix}
$$
对角矩阵
对于$n$阶方阵中$i=j$的那些元素构成了矩阵的主对角线, 方阵中除了主对角线的元素外, 其他元素都为零的矩阵称为对角矩阵.
$$
\boldsymbol{A}=\begin{bmatrix}
a_{11} & 0 & \cdots & 0 \\
0 & a_{22} & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & a_{nn}
\end{bmatrix}
$$
对称矩阵
以主对角线为对称轴两侧元素对称分布的矩阵, 即$a_{ij}=a_{ji},i\neq j$, 这样的矩阵称为对称矩阵.
分块矩阵
我们可以把矩阵分块, 每个块都是一个新的矩阵, 称为子矩阵或者分块.
初等变换
我们可以对矩阵中的行或列进行以下操作($r_i$表示行, $c_i$表示列:
- 互换两行(列): $r_i\leftrightarrow r_j,c_i\leftrightarrow c_j$
- 用一个非零数乘以一行(列): $kr_i, kc_i $
- 一行(列)的元素的某倍加到另一行(列): $r_j+kr_i,c_j+kc_i$
这些操作称为矩阵的初等行(列)变换, 即初等变换.
设 $\boldsymbol{A}$ 是一个矩阵, 若满足以下条件, 则称其为阶梯型矩阵:
- 所有元素全为$0$ 的行(如果存在的话), 都在矩阵的最下方.
- 每一行第一个非零元素(称为首非零元)的列标, 随着行标的增大而严格增大. 也就是说, 若第 $i$ 行的首非零元在第 $j_i$列, 第 $k$ 行的首非零元在第 $j_k$ 列,当 $i < k$时, 有 $j_i < j_k$.
设 $\boldsymbol{A}$ 是一个阶梯型矩阵, 若还满足以下条件,则称$\boldsymbol{A}$为简化阶梯型矩阵(也称为行最简形矩阵):
- 每个首非零元都为1
- 每个首非零元所在列的其余元素都为0
单位矩阵经过一次初等变换得到的矩阵称为初等矩阵.
使用Python能很快的得到简化阶梯型矩阵, 这里我们使用sympy
库:
from sympy.matrices import Matrix
A = Matrix([[1, 2, 3], [4, 5, 6]])
print(f'矩阵A: {A}')
Arref,Apivots=A.rref()
print(f'简化阶梯矩阵: {Arref}')
print(f'主元: {Apivots}')
'''
矩阵A: Matrix([[1, 2, 3], [4, 5, 6]])
简化阶梯矩阵: Matrix([[1, 0, -1], [0, 1, 2]])
主元: (0, 1)
'''
矩阵加法
定义: 设矩阵$(\boldsymbol{A}_{ij})_{m\times n}$和$(\boldsymbol{B}_{ij})_{m\times n}$有相同的形状. $\boldsymbol{C}=\boldsymbol{A}+\boldsymbol{B}$, 则矩阵的元素为$c_{ij}=a_{ij}+b_{ij}$
用二维数组表示矩阵, 加法运算如下:
import numpy as np
a=np.array([[1,3,5],[2,4,6]])
b=np.array([[1,2,3],[4,5,6]])
c=a+b
print(c)
'''
[[ 2 5 8]
[ 6 9 12]]
'''
用np.asmatrix
也可以进行计算
import numpy as np
a=np.asmatrix('1 2 3; 4 5 6')
b=np.asmatrix('1 3 5; 2 4 6')
c=a+b
print(c)
同时也要注意计算时的广播机制, 3×3 的二维数组与长为 3 的一维数组相加, 等效于把数组 b 在二维上重复 3 次再运算
import numpy as np
a = np.array([[0 ,0 ,0 ],
[10,10,10],
[20,20,20]])
b = np.array([0,1,2])
print(a + b)
'''
[[ 0 1 2]
[10 11 12]
[20 21 22]
'''
矩阵的加法也可以转换为向量的加法, 即将矩阵写成向量形式后再进行加法.
矩阵数乘
定义: 矩阵$(\boldsymbol{A}_{ij})_{m\times n}$与标量$c$的数量乘法记为$\boldsymbol{B}=c\boldsymbol{A}$, $(\boldsymbol{A}_{ij})_{m\times n}$和$(\boldsymbol{B}_{ij})_{m\times n}$有相同的形状,且$b_{ij}=ca_{ij}$.
这个时候我们也可以定义矩阵的减法:
$$
\boldsymbol{A}-\boldsymbol{B}=\boldsymbol{A}+(-1)\boldsymbol{B}
$$
用Python操作如下:
import numpy as np
a = np.array([[1, 2], [3, 4]])
b =2 * a
print(b)
'''
[[2 4]
[6 8]]
'''
我们可以把向量的概念进行扩展, 把矩阵也看成一种向量. 两个矩阵的加法符合加法封闭原则, 矩阵的数乘符合乘法封闭原则, 我们可以说$m\times n$的矩阵集合$\mathbb{M}_{mn}$是向量空间.矩阵也可以像向量一样有线性组合的形式.
矩阵乘法
定义: 矩阵$(\boldsymbol{A}_{ij})_{m\times r}$和$(\boldsymbol{B}_{ij})_{r\times n}$相乘, 记作$\boldsymbol{C=AB}$, 其中$\boldsymbol{C}=(c_{ij})_{m\times n}$,$c{ij}=a_{i1}b_{1j}+\cdots+a_{in}b_{nj}=\sum_{k=1}^n a_{ik}b_{kj}$
显然$\boldsymbol{AB}\neq\boldsymbol{BA}$, 交换律不可用.
这时候用numpy
中的数组表示矩阵乘法*
的时候是对应元素相乘, 与矩阵乘法的定义不同.
我们使用np.dot()
来表示矩阵乘法
import numpy as np
a=np.array([[1,2],[3,4]])
b=np.array([[3,4,5],[6,7,8]])
c=np.dot(a,b)
print(c)
'''
[[15 18 21]
[33 40 47]]
'''
或者创建矩阵对象, 这时候就可以用*
了
import numpy as np
a=np.asmatrix('1 2;3 4 ')
b=np.asmatrix('3 4 5;6 7 8')
c=a*b
print(c)
'''
[[15 18 21]
[33 40 47]]
'''
矩阵运算的性质:
- 加法和数乘
- $\boldsymbol{A}+\boldsymbol{B}=\boldsymbol{B}+\boldsymbol{A}$
- $\boldsymbol{A}+(\boldsymbol{B}+\boldsymbol{C})=(\boldsymbol{A}+\boldsymbol{B})+\boldsymbol{C}$
- $\boldsymbol{A}+\boldsymbol{O}=\boldsymbol{O}+\boldsymbol{A}=\boldsymbol{A}$
- $(kl)\boldsymbol{A}=k(l\boldsymbol{A})$
- $(k+l)\boldsymbol{A}=k\boldsymbol{A}+l\boldsymbol{A}$
- $k(\boldsymbol{A}+\boldsymbol{B})=k\boldsymbol{A}+k\boldsymbol{B}$
- 矩阵乘法
- $\boldsymbol{A}(\boldsymbol{BC})=(\boldsymbol{AB})\boldsymbol{C}$
- $\boldsymbol{A}(\boldsymbol{B}+\boldsymbol{C})=\boldsymbol{AB}+\boldsymbol{AC}$
- $(\boldsymbol{A}+\boldsymbol{B})\boldsymbol{C}=\boldsymbol{AC}+\boldsymbol{BC}$
- $\boldsymbol{AI}=\boldsymbol{IA}=\boldsymbol{A}$
- $r(\boldsymbol{AB})=(r\boldsymbol{A})\boldsymbol{B}=\boldsymbol{A}(r\boldsymbol{B})$
方阵还有幂运算
$$
\boldsymbol{A}^k=\underbrace{\boldsymbol{AA}\cdots\boldsymbol{AA}}_{k\text{个}}
$$
性质:
- $\boldsymbol{A}^r\boldsymbol{A}^s=\boldsymbol{A}^{r+s}$
- $(\boldsymbol{A}^r )^s=\boldsymbol{A}^{rs}$
numpy
中的指数运算函数np.power()
并不能完成对方阵的幂运算(哪怕是矩阵对象), 他对里面的元素进行了幂运算, 与我们的定义要求不符.
如果想要进行矩阵指数运算, 可以这么做
from numpy.linalg import matrix_power
import numpy as np
M=np.asmatrix('1 2; 3 4 ')
print(matrix_power(M, 4))
'''
[[199 290]
[435 634]]
'''
或者直接使用**
运算符
import numpy as np
M=np.asmatrix('1 2; 3 4 ')
print(M**4)
我们还有一个重要结论: 初等行变换相当于左乘一个相应的初等矩阵, 初等列变换相当于右乘一个相应的初等矩阵.
线性映射
线性
首先我们定义线性
定义: 如果函数$f(x)$是线性的, 那么他必须满足:
- 可加性: $f(x_1+x_2)=f(x_1)+f(x_2)$
- 齐次性: $f(cx)=cf(x)$
直线不等于线性函数. 对于$n$元函数, 我们有$f(x_1,x_2,\cdots,x_n)=k_1x_1+k_2x_2+\cdots+k_nx_n$
观察以下线性方程组
$$
\begin{cases}
y_1=a_{11}x_1+\cdots+a_{1n}x_n\\
\vdots\\
y_m=a_{m1}x_1+\cdots+a_{mn}x_n
\end{cases}
$$
改写为矩阵形式
$$
\begin{bmatrix}y_1\\ \vdots \\ y_n\end{bmatrix}=\begin{bmatrix}a_{11} & \cdots &a_{1n}\\ \vdots &\ddots & \vdots \\ a_{m1} & \cdots & a_{mn}\end{bmatrix}\begin{bmatrix}x_1\\ \vdots \\ x_n\end{bmatrix}
$$
即
$$
\boldsymbol{y=Ax}
$$
如果将上式看成函数, 其符合线性的要求; 如果看成向量, 则符合加法和数乘封闭, 向量$\boldsymbol{x}$通过矩阵$\boldsymbol{A}$变换成了向量$\boldsymbol{y}$.
在机器学习中线性回归指的则是, 对于如下线性回归模型
$$
\boldsymbol{Y}=\beta_1\boldsymbol{x_1}+\beta_2\boldsymbol{x_2}+\cdots+\beta_n\boldsymbol{x_n}
$$
即$\beta_1\boldsymbol{x_1}+\beta_2\boldsymbol{x_2}+\cdots+\beta_n\boldsymbol{x_n}$是参数$\beta_i$的线性函数, 而非$\boldsymbol{x_i}$的线性函数.
线性映射
映射: 设两个非空集合$\mathbb{A}$和$\mathbb{B}$之间存在着对应关系$\boldsymbol{T}$, 且对于$\mathbb{A}$中的每一个元素$a$, $\mathbb{B}$中总有唯一一个元素$b$与之对应, 这种对应称为从$\mathbb{A}$到$\mathbb{B}$的映射.$b$称为元素$a$在映射$\boldsymbol{T}$下的像, $a$称为$b$关于映射$\boldsymbol{T}$的原像.
线性代数将$\mathbb{R}\mapsto\mathbb{R}$的映射推广到了$\mathbb{R}^n\mapsto\mathbb{R}^m$的映射, 其他函数的概念也得到了推广
函数 | 映射 |
---|---|
函数$f:\mathbb{R}\mapsto\mathbb{R}$ | 线性映射$\boldsymbol{T}: \mathbb{R}^n\mapsto\mathbb{R}^m$ |
输入$x\in\mathbb{R}$ | 输入$\boldsymbol{x}\in\mathbb{R}^m$ |
输出$f(x)\in\mathbb{R}$ | 输出$\boldsymbol{T}(\boldsymbol{x})=\boldsymbol{Ax}\in\mathbb{R}^m$ |
定义: $\mathbb{V}$和$\mathbb{V}’$是实数域上的向量空间, $\mathbb{V}$和$\mathbb{V}’$的一个映射$\boldsymbol{T}$如果具有加法和数乘运算, 即
$$
\boldsymbol{T(u+v)=T(u)+T(v)}\
\boldsymbol{T}(c\boldsymbol{u})=c\boldsymbol{T(u)}
$$
则称$\boldsymbol{T}$为$\mathbb{V}$到$\mathbb{V}’$的线性映射.
我们可以用矩阵表示线性映射, 显然其符合加法和数乘封闭的要求, 符合线性映射的定义.
前面讲过的坐标变换公式$\boldsymbol{x=Px’}$, 表示的正是向量在同一向量空间不同基下的映射.
对于在同一向量空间发生的线性映射, 我们称为线性变换.
矩阵和线性映射
如果将矩阵作为线性映射或线性变换, 以$\boldsymbol{Av}$的形式就能实现$\boldsymbol{v}$的线性映射输出另一个向量.
二维空间中的向量$\begin{bmatrix}x\\y\end{bmatrix}$在标准基$\{\begin{bmatrix}1\\0\end{bmatrix},\begin{bmatrix}0\\1\end{bmatrix}\}$构建的坐标系下经过映射$\boldsymbol{T}=\begin{bmatrix}1 &0\\0 &1\end{bmatrix}$变换为$\begin{bmatrix}x\\-y\end{bmatrix}$, 称为相对$x$轴的对称变换.
来看一个旋转变换的实例, 二维向量空间中, 向量旋转$\theta$角变换为另一个向量.
$$
\begin{bmatrix}x’\\y’\end{bmatrix}=\begin{bmatrix}\cos\theta & -\sin\theta\\\sin\theta & \cos \theta\end{bmatrix}\begin{bmatrix}x\\y\end{bmatrix}
$$
这里$\begin{bmatrix}\cos\theta & -\sin\theta\\\sin\theta & \cos \theta\end{bmatrix}$即为熟悉爱你旋转变换的矩阵.
上面从线性映射的角度讲了矩阵乘向量的含义, 那矩阵乘矩阵呢?
不难推广, $\boldsymbol{AB}$即用映射$\boldsymbol{A}$对矩阵/向量$\boldsymbol{B}$实施线性映射(或线性变换), 矩阵和矩阵的乘法其实就是连续发生的线性映射.
我们可以总结为一句话: 矩阵就是线性映射.
齐次坐标系和仿射变换
平移不是线性变换, 就不能用矩阵的乘法表示. 出于形式的统一, 数学上引入了齐次坐标系, 在笛卡尔坐标系中, 每个点的坐标用$(x,y)$表示, 而在齐次坐标系中变成了$(x’,y’,w)$, 其中$x=x’/w,y=y’/w$, 通常设$w=1$, 这样平移也可以用矩阵乘法表示了.
对于二维向量空间的齐次坐标系, 以下几个矩阵分别实现了齐次坐标中的旋转伸缩平移变换.
- 旋转:$\boldsymbol{A}=\begin{bmatrix}\cos\theta &-\sin\theta &0\\\sin\theta&\cos\theta&0\\0&0&1\end{bmatrix}$,$\theta$表示旋转的角度.
- 伸缩:$\boldsymbol{C}=\begin{bmatrix}r&0&0\\0&r&0\\0&0&1\end{bmatrix}$,$r$为伸缩倍数.
- 平移:$\boldsymbol{E}=\begin{bmatrix}1&0&h\\0&1&k\\0&0&1\end{bmatrix}$,$h,k$分别为$x,y$轴移动的长度.
对于某个向量实现伸缩旋转平移变换则可以写成:
$$
\boldsymbol{EAC}\begin{bmatrix}x\\y\\1\end{bmatrix}=\begin{bmatrix}1&0&h\\0&1&k\\0&0&1\end{bmatrix}\begin{bmatrix}\cos\theta &-\sin\theta &0\\\sin\theta&\cos\theta&0\\0&0&1\end{bmatrix}\begin{bmatrix}r&0&0\\0&r&0\\0&0&1\end{bmatrix}\begin{bmatrix}x\\y\\1\end{bmatrix}\\=\begin{bmatrix}r\cos\theta&-r\sin\theta&hr\cos\theta-kr\sin\theta\\r\sin\theta&r\cos\theta&hr\sin\theta+kr\cos\theta\\0&0&1\end{bmatrix}\begin{bmatrix}x\\y\\1\end{bmatrix}
$$
缩放, 旋转, 平移变换统称为仿射变换.
OpenCV中可以实现图形变换.例如:
平移:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
M = np.float32([[1,0,100 ],[0,1,50]])
#平移变换矩阵
rows,cols,ch=img.shape
res = cv2.warpAffine(img,M,(cols,rows))
#仿射变换函数
plt.subplot(121)
plt.imshow(img)
plt.title('input')
plt.subplot(122)
plt.imshow(res)
plt.title('output')
缩放:
M = np.float32([[0.5,0,0],[0,0.5,0]])
res = cv2.warpAffine(img,M,(row//2,cols//2))
旋转:
M = np.float32([[0.702,-0.702,0],[0.702,0.702,0]])
res = cv2.warpAffine(img,M,(4000,4000))
但是用这种方式进行旋转有个问题, 就是其是按照原点(左上角)为旋转中心旋转, 会造成图片损失居多, 可以使用专用的旋转变换矩阵:
M = cv2.getRotationMatrix2D((rows/2,cols/2),45,1)
#getRotationMatrix2D(center,angle,scale)设置旋转中心, 旋转角度, 缩放角度
res = cv2.warpAffine(img,M,(rows,cols))
矩阵的逆和转置
逆矩阵
定义: 设$\boldsymbol{A}$是$n\times n$的方阵, 如果存在矩阵$\boldsymbol{B}$, 使得
$$
\boldsymbol{AB=BA=I}_n
$$
其中$\boldsymbol{I}_n$是单位矩阵, 我们就说矩阵$\boldsymbol{A}$是可逆的(非奇异的), 称矩阵$\boldsymbol{B}$为$\boldsymbol{A}$的逆矩阵, 记作$\boldsymbol{A}^{-1}$
$$
\boldsymbol{AA}^{-1}=\boldsymbol{A}^{-1}\boldsymbol{A}=\boldsymbol{I}_n
$$
可逆矩阵都是方阵, 单位矩阵的逆矩阵还是单位矩阵.
颜色学中会用到逆矩阵的应用和计算, 使用三个相对独立的向量描述颜色, 组成颜色空间.
- RGB: 通过 Red, Green, Blue三原色来描述颜色的颜色空间. 常用十六进制的6个数字, 如#336699表示一种颜色, 这里的6个数字被分为三组, 即(33,66,99), 分别对应红(R), 绿(G), 蓝(B) 三种颜色. 每种颜色的成分可以用从0到255(十进制)的数表示, 0是最低级, 255是最高级. 此外还可以用诸如 rgb(255,0,0)或rgb(100%,0%,0%)(这两者都表示红色)的形式表示颜色.
- YIQ:是NTSC制式的模拟彩色电视所使用的颜色空间, Y表示图像的亮度, I, Q是色调的两个分量, 1代表从橙色到青色的颜色变化,Q代表从紫色到黄绿色的颜色变化.
- YUV: 是 PAL 制式的模拟彩色电视所使用的颜色空间. Y代表亮度, U,V代表色差, 构成彩色的两个分量. YUV颜色空间将YUV分离,如果只有Y分量而没有UV分量, 那么表示的图像就是黑白灰度图像, 从而让黑白电视机也能接收彩色电视机的信号.
下面为RGB变换为YUV的方式
$$
\begin{bmatrix}
Y \\
U \\
V
\end{bmatrix}
\begin{bmatrix}
0.299 & 0.587 & 0.114 \\
-0.14713 & -0.28886 & 0.436 \\
0.615 & -0.51499 & -0.10001
\end{bmatrix}
\begin{bmatrix}
R \\
G \\
B
\end{bmatrix}
$$
反过来通过逆矩阵就可以有YUV变换为RGB的关系
$$
\begin{bmatrix}
R \\
G \\
B
\end{bmatrix}
\begin{bmatrix}
0.299 & 0.587 & 0.114 \\
-0.14713 & -0.28886 & 0.436 \\
0.615 & -0.51499 & -0.10001
\end{bmatrix}^{-1}
\begin{bmatrix}
Y \\
U \\
V
\end{bmatrix}
$$
当然计算逆矩阵可以通过numpy提供的inv()
函数进行计算.
import numpy as np
from numpy.linalg import inv
a = np.array([[0.299, 0.587, 0.114],
[-0.147, -0.289, 0.436],
[0.615, - 0.515 ,-0.1]])
# 计算矩阵 a 的逆矩阵,并将结果四舍五入到小数点后三位
inverse_a = np.round(inv(a), 3)
print(inverse_a)
逆矩阵有一些性质
- $(\boldsymbol{A}^{-1})^{-1}=\boldsymbol{A}$
- $(c\boldsymbol{A})^{-1}=\dfrac{1}{c}\boldsymbol{A}^{-1}$
- $\boldsymbol{AB}^{-1}=\boldsymbol{B}^{-1}\boldsymbol{A}^{-1}$
- $(\boldsymbol{A}^n)^{-1}=(\boldsymbol{A}^{-1})^n$
- $(\boldsymbol{A}^T)^{-1}=(\boldsymbol{A}^{-1})^T$
- $\boldsymbol{A}^{-k}=\underbrace{\boldsymbol{A}^{-1}\boldsymbol{A}^{-1}\cdots\boldsymbol{A}^{-1}}_{k\text{个}}$
- $\boldsymbol{A}$的各列线性无关
- $\boldsymbol{A}^T$是可逆矩阵
- 当且仅当$|\boldsymbol{A}|\neq0$时, $\boldsymbol{A}$可逆.
转置矩阵
将矩阵$\boldsymbol{A}=(a_{ij})_{m\times n}$的行列互换后所得的矩阵称为$\boldsymbol{A}$的转置矩阵, 记为$\boldsymbol{A}^T$, 转置后第$(i,j)$个元素变成了第$(j,i)$个元素.矩阵的形状由$m\times n$变成了$n\times m$.
如果用np.asmatrix()
创立矩阵用其就可以计算转置矩阵.
import numpy as np
A = np.asmatrix('2 3 5; 7 11 13')
print(A)
print(A.T)
计算结果
[[ 2 3 5]
[ 7 11 13]]
[[ 2 7]
[ 3 11]
[ 5 13]]
如果用二维数组表示矩阵, 则使用np.transpose()
也能得到相同结果.
转置在机器学习中有着重要作用, 这里仅简单提一下在点积中的作用.
设向量$\boldsymbol{u}=\begin{bmatrix}u_1\\\vdots\\u_n\end{bmatrix},\boldsymbol{v}=\begin{bmatrix}v_1\\\vdots\\ v_n\end{bmatrix}$, 则$\boldsymbol{u}^T\boldsymbol{v}=u_1v_1+\cdots+u_nv_n=\boldsymbol{u}\cdot\boldsymbol{v}$
转置矩阵有一些运算性质:
- $(\boldsymbol{A}^T)^T=\boldsymbol{A}$
- $(\boldsymbol{A}+\boldsymbol{B})^T=\boldsymbol{A}^T+\boldsymbol{B}^T$
- $(\boldsymbol{AB})^T=\boldsymbol{B}^T\boldsymbol{A}^T$
- $(c\boldsymbol{A})^T=c\boldsymbol{A}^T$
定义: 矩阵$\boldsymbol{A}$是$n\times n$方阵, 若满足$\boldsymbol{A}^T=\boldsymbol{A}$, 则$\boldsymbol{A}$称为对称矩阵.
其有一个特殊的性质:$\boldsymbol{AB}=(\boldsymbol{AB})^T=\boldsymbol{B}^T\boldsymbol{A}^T=\boldsymbol{BA}$
矩阵$\boldsymbol{LU}$分解
上三角矩阵: 对角线以下的元素都为零的矩阵
下三角矩阵: 对角线以上的元素都为零的矩阵
单位下三角矩阵$\boldsymbol{L}$: 主对角线元素都为1的下三角矩阵.
定义:将$n$阶方阵$\boldsymbol{A}$表示为两个$n$阶三角矩阵的乘积:
$$
\boldsymbol{A}=\boldsymbol{LU}
$$
其中$\boldsymbol{L}$是单位下三角矩阵, $\boldsymbol{U}$是上三角矩阵, 这种形式称为矩阵$\boldsymbol{A}$的$\boldsymbol{LU}$分解.
注:不是所有的可逆矩阵都可以进行$\boldsymbol{LU}$分解, 至少主对角线上的第一个元素不能为零.
如果不能分解, 就引入一个置换矩阵$\boldsymbol{P}$, 即
$$
\boldsymbol{PA}=\boldsymbol{LU}\
\boldsymbol{P}^{-1}\boldsymbol{PA}=\boldsymbol{P}^{-1}\boldsymbol{LU}\
\boldsymbol{A}=\boldsymbol{PLU}
$$
这种分解称为$\boldsymbol{PLU}$分解
对于一个 $n\times n$ 的矩阵 $\boldsymbol{A}$可借助高斯消元法来完成分解。在高斯消元过程中,通过一系列行变换将矩阵 $\boldsymbol{A}$ 转化为上三角矩阵 $\boldsymbol{U}$,而这些行变换所对应的初等矩阵乘积的逆就是下三角矩阵 $\boldsymbol{L}$。
以 $3\times3$ 矩阵为例,设矩阵 $\boldsymbol{A}=\begin{bmatrix}a_{11}&a_{12}&a_{13}\\a_{21}&a_{22}&a_{23}\\a_{31}&a_{32}&a_{33}\end{bmatrix}$,经过一系列消元操作后,会得到下三角矩阵 $\boldsymbol{L}=\begin{bmatrix}1&0&0\\l_{21}&1&0\\l_{31}&l_{32}&1\end{bmatrix}$ 和上三角矩阵 $\boldsymbol{U} = \begin{bmatrix}u_{11}&u_{12}&u_{13}\\0&u_{22}&u_{23}\\0&0&u_{33}\end{bmatrix}$,使得 $\boldsymbol{A} =\boldsymbol{ LU}$.
即$\boldsymbol{L}$记录了行变换的过程, $\boldsymbol{U}$记录了行变换的结果, 即$\boldsymbol{LU}$分解的本质是高斯消元法. 原来的矩阵能用比较简单的矩阵进行表示, 可以简化矩阵的运算.
在scipy
中提供了专用的函数lu()
:
import pprint
from scipy.linalg import lu
import numpy as np
A=np.array([[7,3,-1,2],[3,8,1,-4],[-1,1,4,-1],[2,-4,-1,6]])
P,L,U=lu(A)
print("A:")
pprint.pprint(A)
print("P:")
pprint.pprint(P)
print("L:")
pprint.pprint(L)
print("U:")
pprint.pprint(U)
输出
A:
array([[ 7, 3, -1, 2],
[ 3, 8, 1, -4],
[-1, 1, 4, -1],
[ 2, -4, -1, 6]])
P:
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
L:
array([[ 1. , 0. , 0. , 0. ],
[ 0.42857143, 1. , 0. , 0. ],
[-0.14285714, 0.21276596, 1. , 0. ],
[ 0.28571429, -0.72340426, 0.08982036, 1. ]])
U:
array([[ 7. , 3. , -1. , 2. ],
[ 0. , 6.71428571, 1.42857143, -4.85714286],
[ 0. , 0. , 3.55319149, 0.31914894],
[ 0. , 0. , 0. , 1.88622754]])
行列式
计算方法和意义
行列式是一些按照某种特定方式排列的方阵所确定的一个数.
$$
\begin{vmatrix}
a_{11} & a_{12} & \cdots & a_{1n}\\
a_{21} & a_{22} & \cdots & a_{2n}\\
\vdots&\vdots&\ddots&\vdots\\
a_{n1}&a_{n2}&\cdots&a_{nn}
\end{vmatrix}=\sum_{j_1j_2\cdots j_n}(-1)^{\tau(j_1j_2\cdots j_n)}a_{1j_1}a_{2j_2}\cdots a_{nj_n}
$$
其中$\tau{(j_1j_2\cdots j_n)}$表示逆序数.
这里不再详细介绍.
通常$|\boldsymbol{A}|$或$\det\boldsymbol{A}$表示方阵的行列式.
行列式表征矩阵中线性无关的列向量在空间围成的多面体的体积(二维则退化为平面面积)
矩阵列向量和行列式有如下关系:
$$
矩阵列向量线性无关\leftrightarrow|\boldsymbol{A|}\neq0\
矩阵列向量线性相关\leftrightarrow|\boldsymbol{A|}=0\
$$
行列式的计算可以用NumPy库的np.linalg.det()
函数来实现
import numpy as np
a=np.array([[6,1,1],[4,-2,5],[2,8,7]])
print(np.linalg.det(a))#输出-306.0
行列式也有一些性质如下:
矩阵$\boldsymbol{A}=(a_{ij})_{n\times n}$, $c$为非零的标量, 则:
- $|c\boldsymbol{A}|=c^n|\boldsymbol{A}|$
- $|\boldsymbol{AB}|=|\boldsymbol{A}||\boldsymbol{B}|$
- $|\boldsymbol{A}^T|=|\boldsymbol{A}|$
- $|\boldsymbol{A^{-1}}|=\dfrac{1}{|\boldsymbol{A}|}$
- $|\boldsymbol{A}|=\prod_{i=1}^n\lambda_i$, $\lambda_i$是$\boldsymbol{A}$的特征值
线性方程组
线性方程组是由若干个线性方程组成的方程组. 一般形式可以表示为:
$$
\begin{cases}
a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = b_1 \\
a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = b_2 \\
\vdots \\
a_{m1}x_1 + a_{m2}x_2 + \cdots + a_{mn}x_n = b_m
\end{cases}
$$
其中, $x_1,x_2,\cdots,x_n$ 是未知量( 变量), $a_{ij}$( $i = 1,2,\cdots,m$;$j = 1,2,\cdots,n$)是方程组的系数, $b_1,b_2,\cdots,b_m$ 是常数项. $m$ 表示方程的个数, $n$ 表示未知量的个数, $m$ 和 $n$ 可以相等也可以不相等。
方程组的解是指一组使得方程组中每个方程都成立的未知量的值. 求解线性方程组的方法有很多, 例如高斯消元法, 矩阵变换法等.
也可以简写为
$$
\boldsymbol{Ax=b}
$$
其中$\boldsymbol{A}$为系数矩阵, $\boldsymbol{b}$为方程组等号右侧的常数项, $\boldsymbol{x}$为未知量.
齐次线性方程组
齐次线性方程组是特殊的线性方程组,它的常数项都为 $0$。其一般形式为:
$$
\begin{cases}
a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = 0 \\
a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = 0 \\
\vdots \\
a_{m1}x_1 + a_{m2}x_2 + \cdots + a_{mn}x_n = 0
\end{cases}
$$
齐次线性方程组一定有解, 因为 $x_1 = x_2 = \cdots = x_n = 0$ 就是它的一组解, 称为零解.
判断齐次线性方程组是否有非零解是一个重要的问题, 当系数矩阵的秩 $r(\boldsymbol{A}) < n$($n$ 为未知量个数)时, 齐次线性方程组有非零解;
当 $r(\boldsymbol{A})=n$ 时,只有零解.
未知量和方程个数相同的方程组
当线性方程组中未知量的个数 $n$ 和方程的个数 $m$ 相等时,即 $m = n$,此时方程组的形式为:
$$
\begin{cases}
a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = b_1 \\
a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = b_2 \\
\vdots \\
a_{n1}x_1 + a_{n2}x_2 + \cdots + a_{nn}x_n = b_n
\end{cases}
$$
对于这种方程组,可以通过计算系数矩阵 $\boldsymbol{A}=(a_{ij})$ 的行列式 $|\boldsymbol{A}|$ 来判断解的情况
当 $|\boldsymbol{A}|\neq 0$ 时,方程组有唯一解,可以使用克莱姆法则求解,即 $x_j = \dfrac{|\boldsymbol{A_j}|}{|\boldsymbol{A}|}$($j = 1,2,\cdots,n$),其中 $|\boldsymbol{A}_j|$ 是将系数矩阵 $\boldsymbol{A}$ 的第 $j$ 列元素替换为常数项 $b_1,b_2,\cdots,b_n$ 后得到的行列式.
当 $|\boldsymbol{A}| = 0$ 时, 方程组可能无解或有无穷多解, 需要进一步分析.
关于求解线性方程组的Python解法, 这里不再列出.
矩阵的秩
任何一个矩阵, 其行/列向量能生成空间, 虽然他们是不同维度向量空间的子空间, 但是都是相同维数的子空间, 这个维数表征了矩阵的本色.
定义: 矩阵的列(行)向量生成的子空间维数成为矩阵的列(行)秩, 对于任何矩阵, 列秩等于行秩, 统称为矩阵的秩, 记作$\mathbf{rank}(\boldsymbol{A})$或者$r(\boldsymbol{A})$.
阶梯型矩阵的秩等于非零行的个数, 且主元所在的列构成了列向量组的一个极大线性无关组.
矩阵的初等行变换不改变矩阵的列向量组的线性无关性 , 从而不改变矩阵的列秩
那么我们比较容易算出矩阵的秩
矩阵$\boldsymbol{A}$, 经过初等行变换得到阶梯型矩阵$\boldsymbol{J}$,则$\boldsymbol{A}$的秩等于$\boldsymbol{J}$的非零行个数.
如果$n$阶矩阵的秩为$n$, 那么称其为满秩矩阵.
前面提到过, 如果用矩阵乘以某个向量, 相当于把该向量映射到矩阵的列空间, 即所得向量的维度就是此映射矩阵的秩.
例如$\boldsymbol{T}=\begin{bmatrix}2 &3& 4\\5& 5& 6\\7& 8& 9\end{bmatrix}$,经$\boldsymbol{A}=\begin{bmatrix}1 &0& 0\\0& 1& 0\\0& 0& 0\end{bmatrix}$映射得到
$\boldsymbol{T}’=\boldsymbol{AT}=\begin{bmatrix}1 &0& 0\\0& 1& 0\\0& 0& 0\end{bmatrix}\begin{bmatrix}2 &3& 4\\5& 5& 6\\7& 8& 9\end{bmatrix}=\begin{bmatrix}2 &3& 4\\5& 5& 6\\0&0&0\end{bmatrix}$
接下来我们用np.linalg.matrix_rank()
求矩阵的秩
import numpy as np
T=np.matrix(" 2 3 4;5 5 6;7 8 9")
A=np.matrix("1 0 0;0 1 0;0 0 0")
T2=A*T
rank_T=np.linalg.matrix_rank(T)
rank_A=np.linalg.matrix_rank(A)
rank_T2=np.linalg.matrix_rank(T2)
print(f"rank(T)={rank_T}, rank(A)={rank_A}, rank(T2)={rank_T2}")
'''
rank(T)=3, rank(A)=2, rank(T2)=2
'''
可以通过映射矩阵$\boldsymbol{A}$的秩得到像$\boldsymbol{T}’$的秩.
对于方阵$\boldsymbol{A}_{n\times n}$以下的几个结论相互等效:
- $\boldsymbol{A}$是可逆矩阵
- 方程$\boldsymbol{Ax=b}$有唯一解
- $\boldsymbol{A}$的行(列)线性无关
- $\boldsymbol{A}$的秩为$n$
- $\boldsymbol{A}^T$可逆
- $|\boldsymbol{A}|\neq0$
- $\boldsymbol{AA}^{-1}=\boldsymbol{I}$
稀疏矩阵
稀疏矩阵在机器学习和深度学习中有着比较重要的地位, 这里将其单独拉出来一章探讨
定义与基本概念
稀疏矩阵 (Sparse Matrix) 是指矩阵中大部分元素为零 (或可忽略) 的矩阵. 设矩阵 $\boldsymbol{A} \in \mathbb{R}^{m \times n}$, 若其非零元素个数 $nnz \ll m \times n$, 则称 $\boldsymbol{A}$ 为稀疏矩阵.$nnz$是非零元素个数 (Number of Non-Zeros)
指标 | 公式 | 说明 |
---|---|---|
稀疏度 | $sparsity = 1 – \frac{nnz}{m \times n}$ | 值越大越稀疏 |
密度 | $density = \frac{nnz}{m \times n}$ | 值越小越稀疏 |
稀疏矩阵的生成
手动创建
坐标格式 (COO) 示例
import numpy as np
from scipy.sparse import coo_matrix
# 定义非零元素的位置和值
rows = np.array([0, 1, 2]) # 行索引
cols = np.array([0, 1, 2]) # 列索引
data = np.array([5, 8, 3]) # 元素值
# 创建 COO 格式稀疏矩阵
A = coo_matrix((data, (rows, cols)), shape=(3,3))
print(A.toarray())
输出:
[[5 0 0]
[0 8 0]
[0 0 3]]
自动生成方法
随机稀疏矩阵生成
from scipy.sparse import random
# 生成 1000x1000 稀疏矩阵, 密度 0.1%
A = random(1000, 1000, density=0.001, format='csr')
print(f"非零元素数: {A.nnz}")
稀疏矩阵的压缩存储
压缩原理
通过仅存储非零元素及其位置信息, 减少内存占用:
存储方式 | 稠密矩阵 | 稀疏矩阵 (CSR) |
---|---|---|
存储空间 | $O(mn)$ | $O(nnz + m)$ |
主要压缩格式
(1) COO 格式 (Coordinate Format)
- 数据结构:
class COO:
rows: [i1, i2, ..., innz] # 行索引
cols: [j1, j2, ..., jnnz] # 列索引
data: [v1, v2, ..., vnnz] # 元素值
- 特点: 构建简单, 适合增量修改
(2) CSR 格式 (Compressed Sparse Row)
- 数据结构:
class CSR:
row_ptr: [0, 2, 5, ...] # 行指针数组 (长度 m+1)
cols: [j1, j2, ..., jnnz]
data: [v1, v2, ..., vnnz]
- 寻址公式:
第 $i$ 行的元素范围为cols[row_ptr[i] : row_ptr[i+1]]
(3) CSC 格式 (Compressed Sparse Column)
- 与 CSR 类似,但按列压缩存储
压缩效率对比
格式 | 存储空间 | 适用场景 |
---|---|---|
COO | $3 \times nnz$ | 矩阵构建/转换 |
CSR | $2 \times nnz + m + 1$ | 行操作密集型 |
CSC | $2 \times nnz + n + 1$ | 列操作密集型 |
压缩存储的数学表示
CSR 格式示例
矩阵:
$\boldsymbol{A} = \begin{bmatrix}
0 & 3 & 0 \\
1 & 0 & 4 \\
0 & 2 & 5
\end{bmatrix}$
转换为 CSR 格式:
row_ptr = [0, 1, 3, 5] # 行指针
cols = [1, 0, 2, 1, 2] # 列索引
data = [3, 1, 4, 2, 5] # 元素值
寻址过程:
- 第 0 行:
cols[0:1] = [1]
,data[0:1] = [3]
- 第 1 行:
cols[1:3] = [0,2]
,data[1:3] = [1,4]
存储格式转换代码
from scipy.sparse import csr_matrix
# 稠密矩阵 -> CSR
dense_matrix = np.array([[0,3,0],[1,0,4],[0,2,5]])
csr = csr_matrix(dense_matrix)
# CSR -> COO
coo = csr.tocoo()
print("CSR row_ptr:", csr.indptr)
print("CSR columns:", csr.indices)
print("CSR data: ", csr.data)
输出:
CSR row_ptr: [0 1 3 5]
CSR columns: [1 0 2 1 2]
CSR data: [3 1 4 2 5]
图与矩阵
图的基本概念
图的定义
图(Graph)是由 顶点集合(Vertices)和 边集合(Edges)组成的数学结构, 记为 $G = (V, E)$, 其中:
- $V = {v_1, v_2, …, v_n}$是顶点的集合.
- $E = {e_1, e_2, …, e_m} $是边的集合, 每条边连接两个顶点(可以相同, 称为自环).
图的分类
- 无向图: 边没有方向, 记为 $ (u, v) $, 等价于 $(v, u) $.
- 有向图: 边有方向, 记为 $ \langle u, v \rangle $, 表示从顶点$u$指向$v$.
- 加权图: 边带有权重(数值).
- 简单图: 无自环且无多重边.
基本术语
- 度(Degree): 顶点连接的边数. 对于有向图分为 入度 和 出度.
- 路径: 顶点序列 $ v_1, v_2, …, v_k $, 满足相邻顶点间有边.
- 连通图: 任意两顶点间存在路径.
- 子图: 顶点和边均为原图子集的图.
特殊图
- 完全图: 每对顶点间均有边, 记为 $ K_n $(n 个顶点).
- 树: 无环且连通的图, 边数为 $ n-1 $.
- 二分图: 顶点分为两组, 边仅存在于组间.
邻接矩阵(Adjacency Matrix)
1. 定义
邻接矩阵$\boldsymbol{A}$是描述顶点间邻接关系的方阵, 大小为 $ |V| \times |V|$, 元素$ A_{ij} $表示顶点$i$到 $j$ 的边数.
2. 构造规则
- 无向图: $ A_{ij} = A_{ji} $, 矩阵对称.
- 有向图: $ A_{ij} $示从$i$ 到$j$的边数.
- 加权图: $A_{ij} $为边权重(无边时通常为 0 或 ∞).
3. 例子
无向图邻接矩阵示例: 顶点集合 $V = {1, 2, 3}$, 边集合 $E = {(1,2), (1,3), (2,3)}$
邻接矩阵为:
$$
\boldsymbol{A} = \begin{bmatrix}
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0
\end{bmatrix}
$$
4. 性质
- 矩阵幂的意义: $\boldsymbol{A}^k$的元素 $ (A^k)_{ij}$ 表示从$i$到 $j$ 的长度为$k$ 的路径数.
- 特征值与谱: 邻接矩阵的特征值反映图的结构特性(如连通性).
关联矩阵(Incidence Matrix)
1. 定义
关联矩阵$\boldsymbol{A}$ 描述顶点与边的关联关系, 大小为 $|V| \times |E| $, 元素 $M_{ie} $表示顶点$i$与边 $e$ 的关系.
2. 构造规则
- 无向图: $ M_{ie} = 1 $(若顶点$i$是边$e$的端点), 否则 0.
- 有向图: $M_{ie} = +1 $(顶点$i$是边$e$的起点), $ M_{ie} = -1$(顶点$i$是边$e$的终点), 否则 0.
3. 例子
有向图示例(边 $e_1: 1 \to 2 , e_2: 2 \to 3 , e_3: 3 \to 1$):
$$
\boldsymbol{M} = \begin{bmatrix}
1 & 0 & -1 \\
-1 & 1 & 0 \\
0 & -1 & 1
\end{bmatrix}
$$
4. 应用
- 网络流分析: 基尔霍夫定律(电路理论).
- 图的空间分解: 行空间对应顶点, 列空间对应边.
拉普拉斯矩阵(Laplacian Matrix)
1. 定义
拉普拉斯矩阵$\boldsymbol{L}$是图的重要算子, 定义为:
$$
\boldsymbol{L=D-A}
$$
其中$\boldsymbol{D}$是度矩阵(对角矩阵, $D_{ii} = \text{deg}(v_i) $), $\boldsymbol{A}$是邻接矩阵.
2. 归一化拉普拉斯矩阵
常用形式:
$$
L_{\text{sym}} = D^{-1/2} L D^{-1/2} \quad \text{或} \quad L_{\text{rw}} = D^{-1} L
$$
3. 例子
无向图邻接矩阵为$\boldsymbol{A}$ , 度矩阵 ( $\boldsymbol{D} = \text{diag}(2, 2, 2) $), 则:
$$
L = \begin{bmatrix}
2 & -1 & -1 \\
-1 & 2 & -1 \\
-1 & -1 & 2
\end{bmatrix}
$$
4. 性质
- 对称性: 对无向图, $\boldsymbol{L}$是实对称矩阵.
- 半正定性: 所有特征值非负.
- 零特征值: 零特征值的重数等于图的连通分支数.
- 应用: 谱聚类、图信号处理、热扩散方程.
总结
- 邻接矩阵: 直接描述顶点间连接关系, 适合路径分析.
- 关联矩阵: 描述顶点与边的关系, 适合空间分解.
- 拉普拉斯矩阵: 结合度与邻接信息, 适合谱分析和动态过程建模.
通过矩阵表示, 图论问题可转化为线性代数问题, 为算法设计提供数学基础.
关于图论的Python形式我们以后再探讨.
拾柒bb
真不是鸽太久,是这一块东西有点太多了再加上最近学业紧张所以写的比较少了:(
尽量还是保持一周好几更吧)