2.矩阵专栏
吐槽一下:矩阵本身不难,但是矩阵的写作太蛋疼了 (⊙﹏⊙)汗 还好有 Numpy,不然真的崩溃了…

LaTex有没有一个集成了很多常用 公式以及 推导或者含 题库的在线编辑器?

代码裤子:https://github.com/lotapp/BaseCode

在线编程系:https://mybinder.org/v2/gh/lotapp/BaseCode/master

数学基础:码农眼中的数学之~数学基础

Numpy基础:小白眼中的AI之~Numpy基础

2.1.矩阵的定义

矩阵:是一个按照长方阵列排列的复数或实数集合。

通俗讲就是:把数排成m行n列后,然后用中括号把它们括住,这种形式的组合就是矩阵了~ eg:

比如上面这个示例就是一个 m×n的矩阵(m行n列的矩阵),如果 m=n那么就叫做 n阶方阵,eg:

这个就是 3阶方阵

如果回到中学,老师肯定都是通过一次方程组来引入矩阵(逆天的老师是这么讲的):

如果你方程组都忘记怎么解的话…好吧还是说下吧:“比如这题,可以先把x2移到右边,这样x1就等于一个表达式了(x1=-x2-1),然后带入第二个表达式就可以解出x1和x2了,一次的其实两个表达式就可以解出了,剩下的你可以把值带进去验证一下”

2.2.矩阵的运算(含幂运算)

2.2.1.加、减

加减比较简单,就是对应元素相加减 (只有 行列都相同的矩阵才可以进行)

就不用麻烦的 LaTex一行行打了,咱们用更方便的 NumPy 来演示一下矩阵加法(不懂代码的直接看结果,不影响阅读的)

Numpy有专门的矩阵函数(np.mat),用法和 ndarray差不多,我们这边使用经常使用 ndarray类型,基础忘记了可以去查看一下:Numpy基础

扩展:矩阵的加法运算满足交换律:A + B = B + A (乘法不行)

import numpy as np

创建两个集合

A = np.arange(1,10).reshape((3,3))
B = np.arange(9).reshape((3,3))

print(A)
print("-"*5)
print(B)
[[1 2 3]
[4 5 6]
[7 8 9]]

[[0 1 2]
[3 4 5]
[6 7 8]]

加法

A + B
array([[ 1, 3, 5],
[ 7, 9, 11],
[13, 15, 17]])

和A+B相等

B + A
array([[ 1, 3, 5],
[ 7, 9, 11],
[13, 15, 17]])

减法

A - B
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
################ 变化来了 ################

之前说过 ”只有行列都相同的矩阵才可以进行“ 来验证一下

创建一个2行3列的矩阵

C = np.arange(6).reshape((2,3))
D = np.arange(6).reshape((3,2))

print©
print("-"*5)
print(D)
[[0 1 2]
[3 4 5]]

[[0 1]
[2 3]
[4 5]]

2行3列的矩阵 + 3行2列的矩阵

C + D # 不同形状的矩阵不能进行加运算

ValueError Traceback (most recent call last)

in ()
1 # 2行3列的矩阵 + 3行2列的矩阵
----> 2 C + D # 不同形状的矩阵不能进行加运算

ValueError: operands could not be broadcast together with shapes (2,3) (3,2)
C - D # 不同形状的矩阵不能进行减运算

ValueError Traceback (most recent call last)

in ()
----> 1 C - D # 不同形状的矩阵不能进行减运算

ValueError: operands could not be broadcast together with shapes (2,3) (3,2)
2.2.2.数乘、数除

这个也比较简单,就是和每个元素相乘,eg: 2×A,A原本的每一个元素都扩大了两倍

数除其实就是乘以倒数(1/x)

print(A)
[[1 2 3]
[4 5 6]
[7 8 9]]

比如2×A,A原本的每一个元素都扩大了两倍

2 * A
array([[ 2, 4, 6],
[ 8, 10, 12],
[14, 16, 18]])
print(A)
[[1 2 3]
[4 5 6]
[7 8 9]]

友情提醒:Numpy里面的运算基本上都是针对每一个元素

A / 2
array([[0.5, 1. , 1.5],
[2. , 2.5, 3. ],
[3.5, 4. , 4.5]])
2.2.3.矩阵乘法

矩阵乘法还是要用 LaTex演示一下的,不然有些朋友可能还是觉得比较抽象:(大家有什么好用的LaTex在线编辑器可以推荐的)

拿上面那个方程组来演示一下:

两个矩阵的乘法仅当第一个矩阵A的列数(column)和另一个矩阵B的行数(row)相等才可以进行计算

通过代码看一看

A = np.array([[1,2],[3,4]])
B = np.array([[4,3],[2,1]])

print(A)
print("-"*5)
print(B)
[[1 2]
[3 4]]

[[4 3]
[2 1]]

注意一下,Numpy里面的乘法默认是每个数对应相乘

如果是矩阵相乘可以使用dot()方法

或者你创建矩阵对象,这样×默认就是矩阵乘法了

A.dot(B) # 矩阵A×矩阵B
array([[ 8, 5],
[20, 13]])
程序验证了我们上面的运算结果,还得注意一下:

A×B和 B×A是不一样的,eg:B×A

如果你乘着乘着就忘记到底怎么乘,就把右边的矩阵换成x1,x2,然后就会了

print(A)
print("-"*5)
print(B)
[[1 2]
[3 4]]

[[4 3]
[2 1]]
B.dot(A) # 矩阵B×矩阵A
array([[13, 20],
[ 5, 8]])
################ 变化来了 ################

来验证一下”两个矩阵的乘法仅当第一个矩阵A的列数(column)和另一个矩阵D的行数(row)相等才可以进行计算“

print(A)
print("-"*5)
print(D)
[[1 2]
[3 4]]

[[0 1]
[2 3]
[4 5]]

A有2列 D有3行

A.dot(D) # 不能乘

ValueError Traceback (most recent call last)

in ()
1 # A有2列 D有3行
----> 2 A.dot(D) # 不能乘

ValueError: shapes (2,2) and (3,2) not aligned: 2 (dim 1) != 3 (dim 0)

你反过来就符合A的列数=D的行数了

D.dot(A)
array([[ 3, 4],
[11, 16],
[19, 28]])
2.2.4.幂乘、幂运算

幂乘比较简单,就是每个元素开平方,不一定是方阵

必须是方阵才能进行幂运算,比如 A²=A×A(矩阵相乘前提: 第一个矩阵A的行=第二个矩阵A的列==>方阵)

print(A)
print("-"*5)
print©
[[1 2]
[3 4]]

[[0 1 2]
[3 4 5]]

幂乘(每个元素开平方)

np.power(A,2) # 使用 A**2也一样
array([[ 1, 4],
[ 9, 16]])

幂乘(不一定是方阵)

np.power(C,2)
array([[ 0, 1, 4],
[ 9, 16, 25]])
################ 方阵幂运算 ################

AAA

np.linalg.matrix_power(A,3)
array([[ 37, 54],
[ 81, 118]])

不是方阵就over

np.linalg.matrix_power(C,3)

ValueError Traceback (most recent call last)

in ()
1 # 不是方阵就over
----> 2 np.linalg.matrix_power(C,3)

~/anaconda3/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py in matrix_power(M, n)
137 M = asanyarray(M)
138 if M.ndim != 2 or M.shape[0] != M.shape[1]:
–> 139 raise ValueError(“input must be a square array”)
140 if not issubdtype(type(n), N.integer):
141 raise TypeError(“exponent must be an integer”)

ValueError: input must be a square array
来个小结 + 扩展:

矩阵的加法运算满足交换律: A+B=B+A

矩阵的乘法满足结合律和对矩阵加法的分配律:

结合律: (AB)C=A(BC)

左分配律: (A+B)C=AC+BC

右分配律: C(A+B)=CA+CB

矩阵的乘法与数乘运算之间也满足类似结合律的规律;与转置之间则满足倒置的

分配律: c(A+B)=cA+cB

结合律: c(AB)=(cA)B=A(cB)

矩阵乘法不满足交换律 一般来说,矩阵A及B的乘积AB存在,但BA不一定存在,即使存在,大多数时候 AB≠BA

2.3.特殊矩阵

2.3.1.零矩阵

零矩阵就是所有的元素都是0

import numpy as np

一维

可以指定类型 np.zeros(5,dtype=int)

np.zeros(5) # 完整写法:np.zeros((5,))
array([0., 0., 0., 0., 0.])

二维

np.zeros((2,5))# 建议用元组,官方文档都是元组
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])

三维 ==> 可以这么理解,2个2*5(2行5列)的矩阵

np.zeros((2,2,5))
array([[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]],

[[0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0.]]])

################ 全1矩阵 ################

np.ones(tuple) 用法和np.zeros(tuple)差不多

可以指定类型 np.ones(5,dtype=int)

一维

np.ones(5) # 完整写法 np.ones((5,))
array([1., 1., 1., 1., 1.])

二维,传一个shape元组

np.ones((2,5))
array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])

三维 可以理解为两个二维数组

np.ones((2,2,5))
array([[[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]],

[[1., 1., 1., 1., 1.],
    [1., 1., 1., 1., 1.]]])

################ 指定值矩阵 ################

创建指定值的矩阵:

np.full((3,5),222)
array([[222, 222, 222, 222, 222],
[222, 222, 222, 222, 222],
[222, 222, 222, 222, 222]])

创建指定值的矩阵,浮点类型

np.full((3,5),222.0)
array([[222., 222., 222., 222., 222.],
[222., 222., 222., 222., 222.],
[222., 222., 222., 222., 222.]])
2.3.3.转置矩阵

转置矩阵 :将矩阵的行列互换得到的新矩阵(行列式不变)

m行×n列的矩阵行和列交换后就变成了 n行×m列的矩阵,eg: 3行×2列 ==> 2行×3列

再次提醒:两个矩阵的乘法仅当第一个矩阵A的列数(column)和另一个矩阵B的行数(row)相等才可以进行计算

A = np.arange(6).reshape((2,3))

print(A)
[[0 1 2]
[3 4 5]]

转置矩阵(行列互换)

A.T
array([[0, 3],
[1, 4],
[2, 5]])
B = np.random.randint(10,size=(2,3))

print(B)
[[4 4 7]
[5 3 9]]
################ 验证系列 ################

验证一下(A+B)T=AT+B^T

print(A.T + B.T)
print("-"*5)
print((A+B).T)
[[ 4 8]
[ 5 7]
[ 9 14]]

[[ 4 8]
[ 5 7]
[ 9 14]]

验证一下(A+B)T=AT+B^T

其实也再一次验证了,Numpy运算符默认是对每一个元素的操作

(A+B).T == A.T + B.T
array([[ True, True],
[ True, True],
[ True, True]])
################ 验证系列 ################

把A变成3*2的矩阵,不够元素用0补

reshape:有返回值,不对原始多维数组进行修改

resize:无返回值,会对原始多维数组进行修改

A.resize(3,2)

print(A)
print(B)
[[0 1]
[2 3]
[4 5]]
[[4 4 7]
[5 3 9]]

验证(AB)T=BT×A^T

print((A.dot(B)).T)
print("-"*5)
print((B.T).dot(A.T))
[[ 5 23 41]
[ 3 17 31]
[ 9 41 73]]

[[ 5 23 41]
[ 3 17 31]
[ 9 41 73]]
2.3.3.上三角矩阵和下三角矩阵

上三角矩阵 :主对角线以下都是零的方阵

下三角矩阵 :主对角线以上都是零的方阵

性质(行列式后面会说)

上(下)三角矩阵的行列式为对角线元素相乘
上(下)三角矩阵乘以系数后也是上(下)三角矩阵
上(下)三角矩阵间的加减法和乘法运算的结果仍是上(下)三角矩阵
上(下)三角矩阵的逆矩阵也仍然是上(下)三角矩阵

创建一个5行4列矩阵

A = np.random.randint(10,size=(4,4))

print(A)
[[3 5 2 3]
[7 2 9 6]
[5 1 7 6]
[1 2 8 4]]

上三角

np.triu(A)
array([[3, 5, 2, 3],
[0, 2, 9, 6],
[0, 0, 7, 6],
[0, 0, 0, 4]])

下三角

np.tril(A)
array([[3, 0, 0, 0],
[7, 2, 0, 0],
[5, 1, 7, 0],
[1, 2, 8, 4]])

验证一下最后一个性质

三角矩阵的逆矩阵也仍然是三角矩阵

print(np.triu(A).T)
print(’-’*5)
print(np.tril(A).T)
[[3 0 0 0]
[5 2 0 0]
[2 9 7 0]
[3 6 6 4]]

[[3 7 5 1]
[0 2 1 2]
[0 0 7 8]
[0 0 0 4]]
2.3.4.对角矩阵

对角矩阵 :主对角线之外的元素皆为0的方阵 (单位矩阵属于对角矩阵中的一种)

简单创建

np.diag([3,9,6])
array([[3, 0, 0],
[0, 9, 0],
[0, 0, 6]])
np.diag([2,2,2])
array([[2, 0, 0],
[0, 2, 0],
[0, 0, 2]])
################ 验证系列 ################

np.diag?

print(A)

获取对角元素,然后再生成对角矩阵

B = np.diag(A.diagonal()) #或者 np.diag(np.diag(A))

print(B)
[[3 5 2 3]
[7 2 9 6]
[5 1 7 6]
[1 2 8 4]]
[[3 0 0 0]
[0 2 0 0]
[0 0 7 0]
[0 0 0 4]]
B.dot(B).dot(B)
array([[ 27, 0, 0, 0],
[ 0, 8, 0, 0],
[ 0, 0, 343, 0],
[ 0, 0, 0, 64]])

对角矩阵的矩阵幂运算等于其对应元素的幂运算

B**3
array([[ 27, 0, 0, 0],
[ 0, 8, 0, 0],
[ 0, 0, 343, 0],
[ 0, 0, 0, 64]])
2.3.5.单位矩阵

单位矩阵 :单位矩阵是个方阵(行列相等),从左上角到右下角的对角线(称为主对角线)上的元素均为1。其他全都为0,eg:

任何 矩阵 x 单位矩阵 都等于其 本身 (反过来也一样(这个和1×a=a×1一个道理))

定义一个2行的单位矩阵(列默认和行一致)

np.eye(rows,columns=rows)

np.eye(2)
array([[1., 0.],
[0., 1.]])
################ 验证扩展 ################

可以指定类型

B = np.eye(4,dtype=int)

print(B)
[[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]]
print(A)
[[3 5 2 3]
[7 2 9 6]
[5 1 7 6]
[1 2 8 4]]

任何矩阵 x 单位矩阵 都等于其本身

A.dot(B)
array([[3, 5, 2, 3],
[7, 2, 9, 6],
[5, 1, 7, 6],
[1, 2, 8, 4]])

反过来也一样(这个和1a=a1一个道理)

B.dot(A)
array([[3, 5, 2, 3],
[7, 2, 9, 6],
[5, 1, 7, 6],
[1, 2, 8, 4]])
2.3.6.对称矩阵

对称矩阵 :元素以主对角线为对称轴对应相等的方阵

对称矩阵的转置是它本身:矩阵对角线元素和python numpy矩阵对角线_逆矩阵

A = np.random.randint(10,size=(4,4))

print(A)
[[0 1 6 9]
[1 2 4 7]
[4 8 7 9]
[3 6 8 0]]
B = np.triu(A)
B += B.T - np.diag(A.diagonal())
print(B)
[[0 1 6 9]
[1 2 4 7]
[6 4 7 9]
[9 7 9 0]]

验证一下

B.T == B
array([[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]])
################ 分步解释 ################

创建上三角矩阵

B = np.triu(A)

print(B)
[[0 1 6 9]
[0 2 4 7]
[0 0 7 9]
[0 0 0 0]]

上三角+它的逆矩阵(发现距离对角矩阵只是多加一次对角线上的元素)

B += B.T

print(B)
[[ 0 1 6 9]
[ 1 4 4 7]
[ 6 4 14 9]
[ 9 7 9 0]]

所以减去对角线上的元素,得到对角矩阵

B - np.diag(A.diagonal())
array([[0, 1, 6, 9],
[1, 2, 4, 7],
[6, 4, 7, 9],
[9, 7, 9, 0]])
2.4.逆矩阵

逆矩阵 :设A是数域上的一个n阶方阵,若在相同数域上存在另一个n阶矩阵B,使得: AB=BA=E 则我们称B是A的逆矩阵(表示为矩阵对角线元素和python numpy矩阵对角线_转置_02),而A则被称为可逆矩阵

通俗话讲就是:原矩阵×逆矩阵=逆矩阵×原矩阵=单位矩阵

2.4.1.消元法

可能一看到逆矩阵,大家就想到代数余子式 ,不过逆天要说的是,代数余子式就和我们程序员面试题一样,有些题目就是又繁琐实际运用又没多大意义的题目一样,很多时候面试官都不看面试题一眼,同样的那些出题老师自己解题一般都不会使用。我这边介绍一下方便简单的方法“消元法”

A = np.array([[3,2],[1,2]])

print(A)
[[3 2]
[1 2]]

求A的逆矩阵

np.linalg.inv(A)
array([[ 0.5 , -0.5 ],
[-0.25, 0.75]])
2.4.2.二阶方阵公式

如果只是2阶方阵,有更简单的公式(只能2阶使用,而消元法不受限制)矩阵是否可逆就看分母是否为0

扩展系列:伪逆矩阵

非方阵可以求 伪逆矩阵 AXA=A,XAX=X

判断矩阵是否可逆:

方法很多(比如还可以通过余子式),公式其实有规律,你可以先摸索下(给个提示):


正负
a11a22
+
a12a21


正负
a11a22a33
+
a11a23a32

a12a21a33

a12a23a31
+
a13a21a32
+
a13a22a31

程序比较简单: np.linalg.det(A)

A = np.array([[7, 3, 6],[5, 3, 1]])

print(A)
[[7 3 6]
[5 3 1]]

不等于0就是可逆

np.linalg.det(A)

LinAlgError Traceback (most recent call last)

in ()
1 # 不等于0就是可逆
----> 2 np.linalg.det(A)

~/anaconda3/lib/python3.6/site-packages/numpy/linalg/linalg.py in det(a)
1869 a = asarray(a)
1870 _assertRankAtLeast2(a)
-> 1871 _assertNdSquareness(a)
1872 t, result_t = _commonType(a)
1873 signature = ‘D->D’ if isComplexType(t) else ‘d->d’

~/anaconda3/lib/python3.6/site-packages/numpy/linalg/linalg.py in _assertNdSquareness(*arrays)
209 for a in arrays:
210 if max(a.shape[-2:]) != min(a.shape[-2:]):
–> 211 raise LinAlgError(‘Last 2 dimensions of the array must be square’)
212
213 def _assertFinite(*arrays):

LinAlgError: Last 2 dimensions of the array must be square

必须是方阵的验证

np.linalg.inv(A)

LinAlgError Traceback (most recent call last)

in ()
1 # 必须是方阵的验证
----> 2 np.linalg.inv(A)

~/anaconda3/lib/python3.6/site-packages/numpy/linalg/linalg.py in inv(a)
521 a, wrap = _makearray(a)
522 _assertRankAtLeast2(a)
–> 523 _assertNdSquareness(a)
524 t, result_t = _commonType(a)
525

~/anaconda3/lib/python3.6/site-packages/numpy/linalg/linalg.py in _assertNdSquareness(*arrays)
209 for a in arrays:
210 if max(a.shape[-2:]) != min(a.shape[-2:]):
–> 211 raise LinAlgError(‘Last 2 dimensions of the array must be square’)
212
213 def _assertFinite(*arrays):

LinAlgError: Last 2 dimensions of the array must be square

有时候还是需要求逆矩阵

那就可以求它的伪逆矩阵

X = np.linalg.pinv(A)

print(X)
[[-0.00632911 0.15189873]
[-0.05696203 0.16708861]
[ 0.20253165 -0.26075949]]

AXA=A

A.dot(X).dot(A)
array([[7., 3., 6.],
[5., 3., 1.]])

XAX=X

X.dot(A).dot(X)
array([[-0.00632911, 0.15189873],
[-0.05696203, 0.16708861],
[ 0.20253165, -0.26075949]])
################ 简单说下mat ################

创建一个矩阵

A = np.mat([[3,2],[1,2]])

print(A)
type(A)
[[3 2]
[1 2]]

numpy.matrixlib.defmatrix.matrix

求它的逆矩阵

A.I
matrix([[ 0.5 , -0.5 ],
[-0.25, 0.75]])

A^T

A.T
matrix([[3, 1],
[2, 2]])

*默认就是矩阵乘法

A * A
matrix([[11, 10],
[ 5, 6]])

更多自己查看下帮助文档把,用法和array基本上一样,

我这边只是简单提一下,怕你们不去看(所有和矩阵相关的东西,里面都有封装,很方便)