向量和矩阵
行向量和列向量
如果把向量写成列的形式,则称为列向量,例如:
Matrix([1, 2, 3])
这个向量有3个分量,分别为1、2、3,分量的个数叫做向量的维数
向量的转置运算
Matrix([1, 2, 3]).T
转置运算能将行向量和列向量相互转换
零向量
分量全为0的向量叫零向量
向量的加减法
向量的加减法就是将向量的对应元素相加减,只有维数相同的向量才能做加减法。
Matrix([1, 2, 3])+Matrix([4, 5, 6])
向量与标量相乘(数乘)
5*Matrix([1, 2, 3])
向量的内积(数量积)
Matrix([1, 2, 3]).dot(Matrix([4, 5, 6]).T)
如果两个向量的内积为0,则称它们正交
向量的L-P范数
L1范数
Matrix([1, 2, 3]).norm(1)
L2范数,也称为向量的模,即向量的长度
Matrix([1, 2, 3]).norm(2)
向量的L-P范数是个标量。
零向量
模等于零的向量是零向量,任意级的L-P范数为0就行,也就是各个分量相加等于0
向量与向量 线性相关
对于两个向量,如果存在两个数( 不全为0)分别与这两个向量相乘,使相乘得到的两个向量相加得到一个零向量,则称这两个向量线性相关;如果这两个数不存在,则称这两个向量线性无关。
对于多个向量也一样。
矩阵的秩
矩阵的行向量或列向量,选取其中一个来计算。
算出最多同时有几个向量线性相关。
有几个,矩阵的秩就是几。
满秩的意思是所有的行向量或列向量同时线性相关。
矩阵
下面创建一个2行3列的矩阵:
Matrix( 2, 3, [1, 2, 3, 4, 5, 6])
矩阵的转置
交换矩阵的行和列,保持得到一个新的矩阵的过程叫矩阵的转置。
转置上面的矩阵:
Matrix( 2, 3, [1, 2, 3, 4, 5, 6]).T
方阵
方阵是行数等于列数的矩阵。
例如:
Matrix( 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])
对称矩阵
一个方阵,如果将其转置,得到的矩阵与原矩阵完全相同,则称这个方阵为对称矩阵。
例如:
Matrix( 3, 3, [1, 2, 3, 2, 4, 5, 3, 5, 6])
对角矩阵
在矩阵中,所在的行数和列数相等的全部元素,共同组成矩阵的主对角线。
如果一个矩阵除主对角线上的元素之外的所有元素都为0,则称为对角矩阵。
下面创建一个对角矩阵:
Matrix( 3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3])
单位矩阵
如果一个矩阵的主对角线上的元素为1,其他元素都为0,则称其为单位矩阵。
下面创建一个单位矩阵:
Matrix( 3, 3, [1, 0, 0, 0, 1, 0, 0, 0, 1])
矩阵加减法
两个矩阵必须尺寸相同才能相加减,把对应位置的元素相加减即可。
Matrix( 2, 3, [1, 2, 3, 4, 5, 6]) + Matrix( 2, 3, [1, 2, 3, 4, 5, 6])
矩阵与标量相乘(数乘)
标量与矩阵的每个分量相乘,得到新的矩阵。
Matrix( 2, 3, [1, 2, 3, 4, 5, 6]) * 5
矩阵与矩阵相乘
两个矩阵相乘,第一个矩阵的列数要和第二个向量的行数相等,用第一个矩阵的每个行向量和第二个矩阵的每个列向量做内积,形成结果矩阵的每个元素
Matrix( 2, 3, [1, 2, 3, 4, 5, 6]) * Matrix( 3, 2, [1, 2, 3, 4, 5, 6])
矩阵的逆
如果两个矩阵相乘的结果是一个单位矩阵,则这两个矩阵互为逆矩阵,每个矩阵都是另一个矩阵的逆。
Matrix( 2, 2, [1, 2, 3, 4])**-1
不是所有的矩阵都能求逆,如果一个矩阵的行列式的值为0,则不可逆;如果矩阵满秩,则不可逆。
矩阵的行列式
行列式是一个函数,自变量是个方阵,因变量是一个数。
Matrix( 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]).det()
这个矩阵的行列式为
- 例题:已知矩阵
有3行3列,如果要选取3个互相不在同一行,不在同一列的元素,有几种选法?
答:有3×2×1=6(种)
“3×2×1”简写为“3!”(3的阶乘)
分别选出来,就是
(1,5,9)
(1,6,8)
(2,4,9)
(2,6,7)
(3,4,8)
(3,5,7)
行列式就是一个把这每一组的3个数相乘,再乘以(-1)**n【负1的n次方】,再把每组的积相加得到另一个数的函数。
这个n等于逆序数(逆序数:选取列的顺序中,较大的数在较小的数前面的情况有几种)。
(1,5,9),选取列顺序1,2,3,逆序数0
(1,6,8),选取列顺序1,3,2,逆序数1:(3,2)
(2,4,9),选取列顺序2,1,3,逆序数1:(2,1)
(2,6,7),选取列顺序2,3,1,逆序数2:(2,1)(3,1)
(3,4,8),选取列顺序3,1,2,逆序数2:(3,1)(3,2)
(3,5,7),选取列顺序3,2,1,逆序数3:(3,2)(3,1)(2,1)
最后的计算结果为0。 - 上面的行列式就是不可逆的,下面展示一个可逆的行列式求逆:
它的行列式为
Matrix( 2, 2, [1, 2, 3, 4]).det()
它的逆为
Matrix( 2, 2, [1, 2, 3, 4])**-1
它的逆的行列式为
(Matrix( 2, 2, [1, 2, 3, 4])**-1).det()
你会发现它的行列式与它的逆的行列式互为倒数。
事实上,所有的可逆矩阵都符合这个规律。
- 假如你是一个小学生,告诉你矩阵、矩阵乘法和矩阵的逆的定义,但不告诉你行列式,现在要求你找到一种方法,能将任意一个可逆矩阵和它的逆矩阵分别用一个相同的操作转换成两个数,使这两个数相乘等于1,你会怎么找?
让我们来发明行列式吧!
已知
如何用a,b,c,d表示e,f,g,h呢?
列出方程:
1=ae+bg(1)
0=af+bh(2)
0=ce+dg(3)
1=cf+dh(4)
由(1)得e=(1-bg)/a,g=(1-ae)/b
由(2)得f=(0-bh)/a,h=(0-af)/b
由(3)得e=(0-dg)/c,g=(1-ce)/d
由(4)得f=(1-dh)/c,h=(1-cf)/d
(1-bg)/a=(0-dg)/c,c-bgc=-dga,c=bgc-dga=g(bc-da),g=c/(bc-da)
(0-bh)/a=(1-dh)/c,-bhc=a-dha,a=-bhc+dha=h(-bc+da),h=a/(-bc+da)
同理,
(1-ae)/b=(0-ce)/d,e=d/(-bc+da)
(0-af)/b=(1-cf)/d,f=b/(bc-da)
填回到原矩阵中,就是:
至此,我们求出了逆矩阵。
小学生发现逆矩阵的四个元素的分母都是一样的,顿时来了灵感。
- 小学生对原矩阵进行ad-bc的运算,再对逆矩阵也进行对应位置的计算,分别得到了两个数,ad-bc和1/(ad-bc),这两个数相乘等于1。
小学生同时发现,这个操作换成(ad-bc)的任意非零常数倍都可以得到两个相乘等于1的数。
同样地,对矩阵
求逆(懒得手算,上代码):
cancel(Matrix( 3, 3, [a, b, c, d, e, f, g, h, i])**-1)
发现了什么??
这些元素的分母都一样呢!
- 小学生对原矩阵进行a e i - a f h - b d i + b f g + c d h - c e g的运算,再对逆矩阵也进行对应位置的计算,分别得到了两个数,a e i - a f h - b d i + b f g + c d h - c e g和1/(a e i - a f h - b d i + b f g + c d h - c e g),这两个数相乘等于1。
小学生好像发现了什么,但还不能确定。
现在,问题是,如何得到一个对任意阶矩阵都适用的【任一元素的分母】的通式,这样就能找到这个操作的一个统一的表达了。
怎么找?
对比下面两个矩阵:
我们学过矩阵的数乘,把这个矩阵(1)的逆矩阵乘以这个矩阵(1)的逆矩阵的【任一元素的分母】,再转置:
simplify((Matrix( 3, 3, [a, b, c, d, e, f, g, h, i])**-1)*(a*e*i-a*f*h-b*d*i+b*f*g+c*d*h-c*e*g)).T
发现什么?
(2)式的第一行第一列的位置上有e,f,h,i四个元素,对应(1)式的a元素的位置,如果在(1)式去掉与元素a同一行和同一列的元素,小学生发现刚好剩下e,f,h,i这四个元素。
显然这个规则对位于矩阵的任意位置的元素都成立。
来看下面的
(2)式是(1)式的逆矩阵数乘一个【任一元素的分母】得到的矩阵的转置,它的每个元素刚好等于从(1)式去除这个元素所在行数的行和所在列数的列以后,剩余下的低一阶矩阵的逆矩阵的【任一元素的分母】乘1或乘-1。
乘1还是乘-1,就看这个分子元素在矩阵中的位置:行数和列数,将行数和列数相加,如果得到的是奇数,就乘-1,是偶数,就乘1。
对于这种放之四海而皆准的规则,就是规律,现在规律已经找到。
如果把小学生尝试的这个操作,通过总结规律,抽象出来,就是计算矩阵的行列式,对应上文的“【任一元素的分母】”这个代数式的值。
如果把找到的这个规律,通过下定义,抽象出来,就是余子式和代数余子式。
- sympy计算行列式默认使用Bareiss算法,其复杂度为O(n^3)。知识源头:Bareiss算法
- sympy也内置了LU分解法,就是将矩阵转为上三角或下三角矩阵,然后把主对角线的元素相乘。
特征值与特征向量
对于一个n阶方阵A,如果存在一个数a,和一个非零列向量B,满足
A×B=a×B
那么,a为矩阵A的特征值,B为该特征值对应的特征向量。
假设“I”是一个n阶的单位矩阵,“0”代表零向量,根据上面的定义,能成立下面的线性方程组
(A-a×I)×B=0
其中,(A-a×I)是系数,这个系数是一个矩阵。
这个线性方程,是一个有n个齐次项相加,结果等于零的方程。
这个方程有通解,那就是,B的每一个元素都为0。
如果要找到B的非0解,有个前提条件,就是系数矩阵的行列式必须为0。
|A-a×I|=0
这个系数矩阵有n阶,用行列式公式展开后,这个方程的次数就变为原来的n倍,如果矩阵原来最高次项的次数是1次,那么就是解n次方程。
5次以上的方程没有公式解,在应用中求近似解。
求解矩阵特征值,用的是QR算法和雅可比法。
Matrix([[1, 2], [2, 2]]).eigenvals()
表示这个矩阵一共有2个代数重数为1的特征值(总共有1×1+1×1=2个特征值),分别是:
Matrix([[2, 1], [0, 2]]).eigenvects()
左边的数是特征值,中间的是代数重数,右边的是特征向量列表(在这个例子中特征向量列表只有一个元素)。
表示这个矩阵有1个代数重数为2特征值2(总共有1×2=2个特征值)。
这里的|A-a×I|=(2-a)^2=0
我们试着解这个方程:
求其行列式方程:
(2-a)^2-1*0=0
化简得(2-a)^2=0
解得a=2,次数为2次(有几次,代数重数就是几)
现在再根据这个特征值去求特征向量:
设这个特征向量的两个元素为x,y:
解得y=0,x取任意一个不为0的数都行,都能让这个向量满足"2x+2y不等于0"的条件。(这样算是一组解)
有时候,解不止一组。
矩阵的迹
矩阵主对角线上的元素之和,叫做矩阵的迹。
韦达定理
根据韦达定理,有如下关系成立:
- 矩阵的迹等于矩阵所有特征值之和。
- 矩阵所有特征值的乘积等于矩阵的行列式。
正交矩阵
若两向量的内积为0,则称它们是正交的。
一个n阶矩阵如果满足它的逆等于它的转置(或者说,它的逆矩阵乘以它等于单位矩阵),则称它为正交矩阵。
正交矩阵的行列式为1,它的(行数和列数相同的)行向量和列向量的内积为1,它的(行数和列数不同的)行向量和列向量相互正交。
(单位矩阵是个对角矩阵,也是一个正交矩阵)
矩阵对角化
如何把一个n阶矩阵A对角化呢?
需要找到一个正交矩阵B,用B的逆乘以A,得到的结果再乘以B,最终得到一个对角矩阵C,就实现了矩阵对角化。
这里的B叫做对角化旋转矩阵。
矩阵C的对角线元素为矩阵A的特征值,矩阵B的列为矩阵A的正交化特征向量。
不是所有的矩阵都能被对角化,一个n阶矩阵可以被对角化的充分必要条件是,这个矩阵存在n个线性无关的特征向量。
因此,像协方差矩阵这样的对称矩阵一定可以被对角化。
(A是原矩阵)
A = Matrix([[1, 2], [2, 2]])
B, C = A.diagonalize()
B
(B是对角化旋转矩阵)
C
(C是对角矩阵)
simplify(B**-1*A*B)==C
改成A的分解式:
A==simplify(B*C*B**-1)
奇异值分解(SVD)
矩阵对角化只适用于方阵,如果不是方阵也可以进行类似的分解,这种分解叫做奇异值分解。
假设A是一个m×n的矩阵;
U是一个m×m的正交矩阵,它的列为A×At(At是A的转置)的特征向量(叫做左奇异向量);
C是一个m×n的对角矩阵;
V是一个n×n的正交矩阵,它的列为At×A(At是A的转置)的特征向量(叫做右奇异向量);
Vt是V的转置。
则有:
A==U×C×Vt
对矩阵进行奇异值分解的python代码如下:
from sympy import *
from sympy.abc import *
def mySvd(A:Matrix):
def sort_eig_vet(sym_eig_vet):
sort_eig_vets = sorted(sym_eig_vet, key=lambda x: x[0], reverse=True) # 按照特征值的大小排序特征向量
V2M = Matrix() # 生成空矩阵
for i in sort_eig_vets:
for v in i[2]:
V2M = V2M.row_join(v.normalized())
return V2M
eig_vets = (A.T * A).eigenvects() # 求特征向量
V = sort_eig_vet(eig_vets)
norm_M = diag(*sorted(A.singular_values(), reverse=True))
norm_r = norm_M.rank()
dt = norm_M[0:norm_r, 0:norm_r]
U = eye(A.shape[0])
U[:,0:norm_r] = A * V[:, 0:norm_r] * dt.inv()
VH = V.T
D = zeros(U.shape[1],VH.shape[0])
D[:norm_r,:norm_r] = dt
return U,D,VH
A = Matrix([[1, 1, 1, 0, 0], [2, 2, 2, 0, 0], \
[1, 1, 1, 0, 0], [5, 5, 5, 0, 0], \
[0, 0, 0, 2, 2], [0, 0, 0, 3, 3], \
[0, 0, 0, 1, 1]])
U,C,Vt = mySvd(A)
B = U*C*Vt
print(A == B)
张量
标量是0阶张量
向量是1阶张量
矩阵是2阶张量
?n阶张量