第06讲 矩阵的应用
作者:欧新宇(Xinyu OU)
本文档所展示的测试结果,均运行于:Intel Core i7-7700K CPU 4.2GHz
【学习目标】
矩阵的定义及基本操作 基于矩阵的向量 特殊形态的矩阵 矩阵的四则运算 张量的常用操作 矩阵的分块 矩阵的应用
【本章要点】
一. 从线性变换的角度看矩阵与向量的乘法
1. 基本定义
矩阵与向量的乘法通常可以理解成向量 到向量 的线性变换。
【定义】 对于向量 ,若它能由向量 线性表示,即有:
则称此关系式为向量 到向量 的线性变换,可以写成输出向量 等于系数矩阵 左乘输入向量 :
注意 不一定等于 . 一般而言, 的形式是便于描述向量x的空间位置在矩阵A的作用下进行变换的过程。此 时需要特别注意的是,在进行乘法的时候,矩阵A在左,列向量x在右,即Ax的顺序不能变。正如前面所讲,矩阵与向 量的乘法可以看作是矩阵与矩阵的乘法第一种特征形式,只不过位于后面的矩阵是一个列数为1的特殊矩阵。
对照矩阵与矩阵的乘法规则,我们可以总结矩阵与向量的乘法规则:当把列向量看作是一个列数为1的特殊矩阵时,那 么运算过程就变得比较简单了。
1. 矩阵在左,列向量在右,矩阵的列数和列向量的维数必须相等;
2. 矩阵和列向量相乘的结果也是一个列向量;
3. 矩阵的行数就是结果向量的维数;
4. 乘法运算的实施过程就是矩阵的每行和列向量的对应元素分别相乘后,再进行相加。
2. 多次线性变换等价于矩阵连乘
设 可写成 ,且
可写成 。
则有:
3. 从矩阵乘法的角度看线性方程组
线性方程组 可以看成是系数矩阵A与输入变量x的乘积: 。
其中, , ,
【例3.13】 给出一个矩阵与向量相乘的例子: .
下面给出Python描述:
【结果分析】
从程序运行的结果来看,原始向量 表示二维平面的一个点,其在二维平面中的坐标为 A(3, 4),经过与矩阵 的乘法运算后,最终将原始点 A 转换为新的目标点B,其空间坐标为B(11,32,53)。
从以上的例子可以总结出矩阵所发挥的重要作用:
在指定矩阵的作用下,原始空间中的向量被映射转换到了目标空间的新坐标,向量的空间位置由此发生了变 化,甚至在映射后,目标空间的维数想较于原始空间都有可能发生改变。
二. 从向量的角度看矩阵乘法
1. 行空间和列空间
如果A是一个 的矩阵,A的每一行为一个实的n元组,于是可以将其看成是 中的一个向量。对应于A的 个行的向量称为A的行向量(row vector),记作:
类似地,A的每一列可以看成是 中的一个向量,且称这 个向量为A的列向量(column vector),记作:
import numpy as np A = np.array([[1,2], [4,5], [7,8]]) x = np.array([[3,4]]).T print(np.dot(A,x))
[[11]
[32]
[53]]
【定义】 如果A为一个 的矩阵,由A的行向量张成的 的子空间称为A的行空间(row space)。由A的各列张 成的 的子空间称为A的列空间(column space)。
【例3.14】 令 ,则:
A的行空间有如下形式的三元组:
A的列空间是所有如下形式的向量:
因此,A的行空间为一个 的二维子空间,且A的列空间为 。
2. 基于行视角的矩阵乘法
下面我们来回顾一下矩阵和向量相乘的运算法则。假设存在一个 维向量 和一个 的矩阵 ,它们相乘的规则如 下:
不难发现,矩阵 第 行的行向量的各成分和列向量 各成分分别相乘后再相加,得到的就是结果向量 中的第 个成 分。这个计算方法就是多次应用了向量点乘的定义式,即:
对于矩阵和向量的乘法运算,以上就是按行计算的展示,这也是常规的计算规则。但看上去只是一种规范性的计算法 则,并没有太多的几何意义和内涵。下面我们给出另外一种从列的视角来解释的矩阵乘法。
3. 基于列视角矩阵乘法
我们依然以一个 维向量 和一个 的矩阵 的乘法为例:
基于这样的拆解方式,依然可以得到正确的结果。
不难发现的是,矩阵 第 列的列向量的各成分和列向量 对应的第 行相乘,得到的是结果向量 中的第 个成分。
相乘的运算就简化成了两个向量的点乘,即:
。
这个结果很有趣,从列的角度来看,矩阵 与向量 的乘法,实质上对矩阵A的各个列向量进行线性组合的过程,每个 列向量的系数就是向量 的各个对应成分。
【例3.15】 给出矩阵乘法
通过乘法计算,最终所得到的结果向量是:位于矩阵第一列的列向量 的3倍加上位于第二列的列向量的 的5 倍。
【小节】
成本(元) 产品A 产品B 产品C 产品 夏 秋 冬 春
原材料 0.1 0.3 0.15 A 4000 4500 4500 4000
劳动 0.3 0.4 0.25 B 2000 2600 2400 2200
企业管理费 0.1 0.2 0.15 C 5800 6200 6000 6000
综上所述,一个矩阵和一个向量相乘的过程可以理解为:对位于原矩阵各列的列向量重新进行线性组合的过程,而在线性 组合的运算过程中,结果中的各个系数就是乘法运算的列向量中所对应的各个成分。这是一种从列的角度去看待矩阵 与向量乘法的新视角。
三. 矩阵的应用案例
矩阵的应用非常广泛,下面给出若干例子。
【例3.16】 特殊矩阵的生成
生成特殊规则的矩阵,可用单列乘单行的矩阵乘法。如:
基本思路:可令 (10行1列),
则 是一个 的矩阵。下面给出Python描述。
【例3.17】生产成本核算问题
某厂生产三种产品,它的成本分为三类。每一类成本中,给出生产单个产品时估计需要的量。同时给出每季度生产每 种产品数量的估计。该公司希望在股东会上用一个表格展示出每一季度三类成本的数量:原料费、工资和管理费。
import numpy as np
v1 = np.array([np.linspace(-10,10,21,dtype=int)]) v2 = np.array([np.linspace(1,1,10)])
X = np.dot(v2.T,v1) print(X.shape) print(X)
(10, 21)
[[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]
[-10. -9. -8. -7. -6. -5. -4. -3. -2. -1. 0. 1. 2. 3.
4. 5. 6. 7. 8. 9. 10.]]
成本(元) 夏 秋 冬 春 全年
原材料 1870 2160 2070 1960 8060
劳动 3450 3940 3810 3580 14780
企业管理费 1670 1900 1830 1740 7140
总成本 6990 8000 7710 7280 29980
解:我们用矩阵的方法来考虑此问题,设产品分类成本矩阵为M,季度产量矩阵为P,则有:
,
如果按 构造乘积,则MP的第一列表示夏季的成本。
原料费:
工资:
管理费和其他:
MP的第二列表示秋季的成本。
原料费:
工资:
管理费和其他:
MP的第三列和第四列表示冬季和秋季的成本。
MP第一行的元素表示四个季度原料的总成本,第二和第三行的元素分别表示四个季度中每一季度工资和管理的成本。
每一类成本的年度总成本可由矩阵的每一行元素相加得到。每一列元素相加,即可得到每一季度的总成本。下表汇总 了总成本。
下面给出Python的计算方法。
import numpy as np import pandas as pd
M = np.array([[0.1,0.3,0.15],[0.3,0.4,0.25],[0.1,0.2,0.15]])
P = np.array([[4000,4500,4500,4000],[2000,2600,2400,2200],[5800,6200,6000,6000]]) Q = np.dot(M,P)
# 将numpy数组转换为DataFrame df = pd.DataFrame(Q)
# 添加行列的标题
df.columns = ['夏','秋','东','春']
df.index = ['原材料','劳动','企业管理费']
# 计算各列数据总和并作为新列添加到末尾
df['全年'] = df.apply(lambda x:x.sum(), axis=1)
# 计算各列数据总和并作为新行添加到末尾
df.loc['总成本'] = df.apply(lambda x:x.sum())
# 输出pandas数据 display(df)
.dataframe tbody tr th { vertical-align: top;
}
.dataframe thead th { text-align: right;
}
某城镇中,有8000位已婚女性和2000位单身女性,假设每年有30%的已婚女性离婚,20%的单身女性结婚。假设所有女性的总数 为一常数,试求1年后有多少已婚女性和单身女性?2年后呢?10年后呢?
解:
首先,我们可以用如下的思路构建矩阵A。
1). 矩阵A的第一行元素分别为1年后仍处于婚姻状态的已婚女性和已婚的单身女性百分比;
2). 第二行元素分别为1年后离婚的已婚女性和未婚的单身女性的百分比。则:
若令 ,则1年后已婚女性和单身女性人数可以用 乘以 计算. 其中8000*0.7表示仍然在婚姻状态的已婚女性,
2000*0.2为转变为已婚的单身女性,两者相加就是1年后已婚女性的总人数;8000*0.3表示1年后离婚的已婚女性,
2000*0.8表示仍然未婚的未婚女性,两者相加就是1年后未婚女性的总人数。
1年后将有6000位已婚女性,4000位单身女性。
其次,要求2年后已婚女性和单身女性的数量,计算
2年后,一半的女性将为未婚,一般的女性将为单身。
最后,讨论一般情况,n年后已婚女性和单身女性的数量可由 求得。
按照以上的分析,我们将使用Python代码实现后续的计算,求解10年后的已婚女性和单身女性的数量。
夏 秋 东 春 全年
原材料 1870.0 2160.0 2070.0 1960.0 8060.0 劳动 3450.0 3940.0 3810.0 3580.0 14780.0 企业管理费 1670.0 1900.0 1830.0 1740.0 7140.0 总成本 6990.0 8000.0 7710.0 7280.0 29980.0
【例3.18】 婚姻状况计算模型
import numpy as np
A = np.array([[0.7,0.2],[0.3,0.8]]) x = np.array([[8000],[2000]])
n = 10 # n=1:A^2; n=2:A^3 product = x
for i in range(n):
product = np.dot(A, product)
print('第{}年,已婚女性{}人,未婚女性{}人'.format(i+1, product[0][0],product[1][0]))
【结果分析】
由程序的输出结果可知,10年后已婚女性和诞生女性的数量分别为:4016人和5984人。
在电路设计中,经常要把复杂的电路分割为局部电路,每一个电路都用一个网络“黑盒子”来表示。“黑盒子”的输入为 , ,输出 为 , ,都有两个变量,因此其输入输出关系用2×2矩阵 来表示(如图), 被称为该电路的传输矩阵。
$\begin{bmatrix} u_2 \\ i_2 \end{bmatrix}
=A\begin{bmatrix} u_1 \\ i_1 \end{bmatrix}$
传输矩阵的元素可以用理论计算,也可用实验测试的方法取得。把复杂的电路分成许多串接局部电路,分别求出或测出它们的传 输矩阵,再相乘起来,得到总的传输矩阵,可以使分析和测量电路的工作简化。
给出如下电路图,同时已知输入电流 和输入电压 ,并且已知四个电阻的电阻值,求输出电流 和输出电压 。
为了求输出电流、电压,我们可以将以上电路图抽象化为黑盒图,并拆分成不同电路模块的组合,再通过矩阵乘法求解最终的输 出矩阵。如下图所示,其中 、 为串联电路, 、 为并联电路。
首先给出一个简化版的例子:
1. 求第一个子网络(串联电路)的传输矩阵 1). 根据电路原理可以得到
2). 将公式转换为矩阵方程
【例3.19】 网络的矩阵分割和连接
第1年,已婚女性6000.0人,未婚女性4000.0人 第2年,已婚女性5000.0人,未婚女性5000.0人 第3年,已婚女性4500.0人,未婚女性5500.0人 第4年,已婚女性4250.0人,未婚女性5750.0人 第5年,已婚女性4125.0人,未婚女性5875.0人 第6年,已婚女性4062.5人,未婚女性5937.5人 第7年,已婚女性4031.25人,未婚女性5968.75人 第8年,已婚女性4015.625人,未婚女性5984.375人 第9年,已婚女性4007.8125人,未婚女性5992.1875人 第10年,已婚女性4003.90625人,未婚女性5996.09375人
3). 获得第一个子网络的传输矩阵,即单一串联电路的传输矩阵。
2. 求第二个子网络(并联电路)的传输矩阵 1). 根据电路原理可以得到
2). 将公式转换为矩阵方程
3). 获得第二个子网络的传输矩阵,即单一并联电路的传输矩阵。
3. 求总电路的传输矩阵
1). 联立以上两个网络获得输入输出的关系
2). 获得总电路传输矩阵
3). 利用传输矩阵求输出电压和输出电流
下面给出矩阵乘法 的Python描述。
【原题解答思路】
对于由单一电路构成的集成电路,我们可以使用矩阵连乘的方法进行求解,值得注意的是多个单一电路合并时的顺序与矩阵连乘 的顺序密切相关。事实上,对于复杂电路也可以用类似的方法求解。
import numpy as np from sympy import *
R1 = Symbol('R1', real=True) R2 = Symbol('R2', real=True)
A1 = np.array([[1,-R1],[0,1]]) A2 = np.array([[1,0],[-1/R2,1]])
A = np.dot(A2,A1)
print('A = \n {}'.format(A))
A = [[1 -R1]
[-1/R2 R1/R2 + 1]]
求最终的变换矩阵
给出最终的输出电压和输出电流 import numpy as np
from sympy import *
R1 = Symbol('R1', real=True) R2 = Symbol('R2', real=True)
A1 = np.array([[1,-R1],[0,1]]) A2 = np.array([[1,0],[-1/R2,1]])
A = [A2,A1,A1,A2]
A_OUT = 1 for i in A:
A_OUT = np.dot(A_OUT,i)
print('A_OUT = \n {}'.format(A_OUT))
A_OUT =
[[2*R1/R2 + 1 -2*R1]
[-(2*R1/R2 + 1)/R2 - 1/R2 2*R1/R2 + 1]]
u0 = Symbol('u0', real=True) i0 = Symbol('i0', real=True) IN = np.array([[u0], [i0]]) OUT = np.dot(A_OUT, IN)
print('输出电压 = {} 伏特'.format(OUT[0][0])) print('输出电流 = {} 安培'.format(OUT[1][0]))
输出电压 = -2*R1*i0 + u0*(2*R1/R2 + 1) 伏特
输出电流 = i0*(2*R1/R2 + 1) + u0*(-(2*R1/R2 + 1)/R2 - 1/R2) 安培