欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线性代数(4)——矩阵进阶

程序员文章站 2022-07-12 14:11:38
...

矩阵——系统

矩阵看做是一个系统,使用矩阵可以表示一个线性系统。如使用矩阵表示一个方程组,
{xi+0.2xj+0.1xk+0.5xl=1000.5xi+xj+0.2xk+0.1xl=500.4xjxk+0.3xl=200.2xi+xl=666\begin{cases}x_i+0.2x_j+0.1x_k+0.5x_l=100\\-0.5x_i+x_j+0.2x_k+0.1x_l=50\\-0.4x_j-x_k+0.3x_l=20\\-0.2x_i+x_l=666\\\end{cases}
可以表示为,
(10.20.10.50.510.20.100.410.30.2001)(1005020666) \begin{pmatrix}1&-0.2&0.1&0.5\\-0.5&-1&0.2&0.1\\0&-0.4&-1&0.3\\-0.2&0&0&1\end{pmatrix} \begin{pmatrix}100\\50\\20\\666\end{pmatrix}

矩阵乘法

矩阵和向量的乘法

上一节中的线型方程组可以使用矩阵和向量表示,
(10.20.10.50.510.20.100.410.30.2001)(xixjxkxl)=(1005020666) \begin{pmatrix}1&-0.2&0.1&0.5\\-0.5&-1&0.2&0.1\\0&-0.4&-1&0.3\\-0.2&0&0&1\end{pmatrix} \begin{pmatrix}x_i\\x_j\\x_k\\x_l\end{pmatrix} =\begin{pmatrix}100\\50\\20\\666\end{pmatrix}
矩阵和向量相乘最终得到的是一个向量,
Ax=bA\cdot\vec{x}=\vec{b}
*每次从矩阵中取出一个行向量与列向量进行点乘,可以简单表示为,
(a11a12...a1na21a22...a2n............am1am2...amn)(u1u2...un)=(a11u1+a12u2+...+a1nuna21u1+a22u2+...+a2nun...am1u1+am2u2+...+amnun) \begin{pmatrix}a_{11}&a_{12}&...&a_{1n}\\a_{21}&a_{22}&...&a_{2n}\\...&...&...&...\\a_{m1}&a_{m2}&...&a_{mn}\end{pmatrix}\cdot\begin{pmatrix}u_1\\u_2\\...\\u_n\end{pmatrix}=\begin{pmatrix}a_{11}u_1+a_{12}u_2+...+a_{1n}u_n\\a_{21}u_1+a_{22}u_2+...+a_{2n}u_n\\...\\a_{m1}u_1+a_{m2}u_2+...+a_{mn}u_n\end{pmatrix}
前提是矩阵的列数与向量的元素个数相同

对于矩阵的行数没有要求。矩阵与向量的点乘可以看做是矩阵将一个向量转换为另一个向量的过程,所以矩阵实际上可以看做是向量的函数(这一视角非常重要)。

矩阵和矩阵的乘法

矩阵AA和矩阵BB的乘法可以将第二个矩阵BB拆成多个列向量,进行矩阵AA和多个列向量的乘法。要求矩阵AA的列数与矩阵BB的行数一致
AB=A(c1c2...cn)=(Ac1Ac2...Acn) A\cdot B=A\cdot \begin{pmatrix}|&|&&|\\\vec{c_1}&\vec{c_2}&...&\vec{c_n}\\|&|&&|\end{pmatrix}=\begin{pmatrix}|&|&&|\\ A\cdot \vec{c_1}&A\cdot \vec{c_2}&...&A\cdot \vec{c_n}\\|&|&&|\end{pmatrix}
等同于,
AB=(r1r2...rm)(c1c2...cn)=(r1c1r1c2...r1cnr2c1r2c2...r2cn.........rmc1rmc2...rmcn) A\cdot B=\begin{pmatrix}-&\vec{r_1}&-\\-&\vec{r_2}&-\\&...\\-&\vec{r_m}&-\end{pmatrix} \cdot\begin{pmatrix}|&|&&|\\\vec{c_1}&\vec{c_2}&...&\vec{c_n}\\|&|&&|\end{pmatrix}=\begin{pmatrix}\vec{r_1}\cdot\vec{c_1}&\vec{r_1}\cdot\vec{c_2}&...&\vec{r_1}\cdot\vec{c_n}\\\vec{r_2}\cdot\vec{c_1}&\vec{r_2}\cdot\vec{c_2}&...&\vec{r_2}\cdot\vec{c_n}\\...&...&&...\\\vec{r_m}\cdot\vec{c_1}&\vec{r_m}\cdot\vec{c_2}&...&\vec{r_m}\cdot\vec{c_n}\\\end{pmatrix}
但是矩阵乘法不满足乘法交换律,即使是方阵,交换律得到的结果也是不相等的。这一点很重要。

矩阵乘法实现

接之前Matrix类代码,

	def dot(self, another):
		"""
		返回矩阵乘法结果
		:param another: Vector类或Matrix类对象
		"""
		if isinstance(another, Vector):
			# 保证矩阵的列数与向量的元素数目相同
			assert self.col_num() == len(another)
			return Vector([self.row_vector(i)*another] for i in range(self.row_num()))
			
		if isinstance(another, Matrix):
			assert self.col_num() == another.row_num()
			return Matrix([[self.row_vector(i).dot(another.col_vector(j)) for j in range(another.col_num())] for i in range(self.row_num())])

矩阵乘法的性质与矩阵的幂

  1. 矩阵乘法不遵守乘法交换律
    ABBAA\cdot B \neq B\cdot A
  2. 矩阵乘法遵守结合律
    (AB)C=A(BC)(A\cdot B)\cdot C=A\cdot (B\cdot C)
  3. 矩阵乘法遵守分配律
    A(B+C)=AB+ACA\cdot(B+C)=A\cdot B+A\cdot C
    (B+C)A=BA+CA(B+C)\cdot A=B\cdot A +C\cdot A
    注意,这两条不等价
  4. 对任意rcr\cdot c的矩阵AA,必存在cxc\cdot x的矩阵OO(零矩阵),满足
    AOcx=OrxA \cdot O_{cx} = O_{rx}
  5. 对任意rcr\cdot c的矩阵AA,必存在xrx\cdot r的矩阵OO(零矩阵),满足
    OxrA=OxcO_{xr}\cdot A = O_{xc}

引入矩阵的幂,对于一个实数而言,其k次幂是k个该数相乘的结果。这对于矩阵也是同理的,
Ak=AA...AkAA^k=\underbrace{A\cdot A\cdot ...A}_{k个A}
前提是AA是方阵,否则无法计算矩阵的幂。

矩阵的转置

矩阵的转置实际上就是将矩阵沿着主对角线旋转,将之前的矩阵的列变成新矩阵的行,之前矩阵的行变为新矩阵的列。矩阵转置满足如下性质,
(AT)T=A(A^T)^T=A
(A+B)T=AT+BT(A+B)^T=A^T+B^T
(kA)T=kAT(k\cdot A)^T=k\cdot A^T
(AB)T=BTAT(A\cdot B)^T=B^T\cdot A^T
最后一条性质的形式与其他三条不同,给出如下证明,
AmkBknA是m\cdot k的矩阵,B是k \cdot n的矩阵
ABmnATBTnmBTATmnA\cdot B是m \cdot n的矩阵,A^T\cdot B^T是n\cdot m的矩阵,B^T\cdot A^T是m\cdot n的矩阵
转置的实现,

    def T(self):
        """
        返回矩阵的转置矩阵
        """
        return Matrix([[e for e in self.col_vector(i)] for i in range(self.col_num())])

Numpy中的矩阵运算

import numpy as np


if __name__ == "__main__":
    # 矩阵的创建
    A = np.array([[1, 2], [3, 4]])
    # 矩阵形状
    print(A.shape)
    # 矩阵的转置
    print(A.T)
    # 获取矩阵元素
    print(A[1, 1])    # 返回4
    print(A[0])       # 返回第一行,或者写 A[0, :]
    print(A[:, 0])    # 返回第一列

    B = np.array([[5, 6], [7, 8]])
    # 矩阵加法
    print(A + B)      # 返回 [[6, 8], [10, 12]]
    # 矩阵数乘
    print(10 * B)

    # 矩阵与向量乘法
    p = np.array([10, 100])

    # 矩阵乘法
    print(A * B)      # 返回element-wise的结果 [[5, 12], [21, 32]]
    print(A.dot(B))   # 返回真正的矩阵乘法结果 [[19, 22], [43, 50]]

numpy中矩阵和矩阵、矩阵和向量之间的运算使用的都应使用 np.dot 方法。