二元一次方程组的未知数的阶数都是一次,式子两边都是用等式相连,因此我们给这个方程组起另一个名字:线性方程组.
什么是向量
矩阵的简介
例如,求解如下二元一次方程组,(方程组可以用向量形式表示成)
我们尝试使用python解线性方程组,Numpy中已经封装了求解线性方程组的函数,我们仅需要传入对应的系数矩阵
A
mathbf{A}
A以及常数向量
b
b
b,程序就会算出相应的结果.
import numpy as np
A = np.array([[1, 1],
[2, 4]]) # 将系数所有向量拼在一起
b = np.array([10,
28]) # 常数向量
x = np.linalg.solve(A,b) # 解线性方程组
print("线性方程组的解为:n",x)
(二) 向量空间、矩阵、行列式以及范数
2.1 向量的运算法则
- 一个数乘一个向量;
- 一个向量加一个向量;
显然,当变量个数变多之后,也会满足上面这两种运算法则,因此我们接下来正式引入向量的基本运算法则:
给定
n
n
n维向量
x
=
[
x
1
x
2
⋮
x
n
]
,
y
=
[
y
1
y
2
⋮
y
n
]
x= begin{bmatrix} {x_1}\ {x_2}\ {vdots}\ {x_n} end{bmatrix}, y= begin{bmatrix} {y_1}\ {y_2}\ {vdots}\ {y_n} end{bmatrix}
x=⎣⎢⎢⎢⎡x1x2⋮xn⎦⎥⎥⎥⎤,y=⎣⎢⎢⎢⎡y1y2⋮yn⎦⎥⎥⎥⎤
-
向量的加法定义为:
x + y = [ x 1 + y 1 x 2 + y 2 ⋮ x n + y n ] , x+y = begin{bmatrix} {x_1 + y_1}\ {x_2 + y_2}\ {vdots}\ {x_n + y_n} end{bmatrix}, x+y=⎣⎢⎢⎢⎡x1+y1x2+y2⋮xn+yn⎦⎥⎥⎥⎤,
即两个向量对应的分量相加. -
向量的数乘定义为:
对于 k ∈ R k in mathbf{R} k∈R,
k x = [ k x 1 k x 2 ⋮ k x n ] , kx = begin{bmatrix} {kx_1 }\ {kx_2}\ {vdots}\ {kx_n} end{bmatrix}, kx=⎣⎢⎢⎢⎡kx1kx2⋮kxn⎦⎥⎥⎥⎤,
即每个分量都乘上 k k k.
关于向量与向量的乘法,我们约定一个使用习惯,我们默认所有的向量都采用列向量的形式,当我们在文中书写时,为了排版优美,通常将向量由列向量转成行向量进行书写,向量的行列交换的称为向量的转置,记做 x T = ( x 1 , x 2 , ⋯ , x n ) x^T = (x_1, x_2, cdots, x_n) xT=(x1,x2,⋯,xn).我们使用Numpy实现向量之间的基本计算.
import numpy as np
# 生成向量
x = np.array([1, 2, 3]) # array默认如果只有一列,就是一个向量
y = np.array([4, 5, 6])
print("x={},y={}".format(x, y))
print("x的维度为{}".format(x.shape)) # shape函数用于显示向量的维度,如果是向量默认只有一维,维度显示为(dim,)
# 向量加法
print("x+y = {}".format(x + y))
# 向量数乘
k = 3
print("kx = {}".format(k*x))
print("3x+2y ={} ".format(3*x + 2*y))
2.2 向量的线性相关与线性无关
研究向量的工具 —— 向量的线性相关与线性无关
给定一组向量
(
α
1
,
α
2
,
⋯
,
α
k
)
(alpha_1, alpha_2, cdots, alpha_k)
(α1,α2,⋯,αk)(注意,这个地方之所以没有转置符号,是因为这是一个向量组,每个
α
alpha
α都是一个列向量,需要与向量的写法做区分),对于向量
β
beta
β,如果能被存在一组不全为0的常数
m
1
,
m
2
,
⋯
,
m
k
m_1, m_2, cdots, m_k
m1,m2,⋯,mk,使得
β
=
m
1
α
1
+
m
2
α
2
+
⋯
+
m
k
α
k
beta = m_1alpha_1 + m_2alpha_2 + cdots + m_kalpha_k
β=m1α1+m2α2+⋯+mkαk
则称向量
β
beta
β与向量组
(
α
1
,
α
2
,
⋯
,
α
k
)
(alpha_1, alpha_2, cdots, alpha_k)
(α1,α2,⋯,αk)是线性相关的,或称
β
beta
β可以被向量组
(
α
1
,
α
2
,
⋯
,
α
k
)
(alpha_1, alpha_2, cdots, alpha_k)
(α1,α2,⋯,αk)线性表出.一旦向量是线性相关的,也就说明“
β
beta
β是一个多余的向量,因为它可以由其他的向量去表示”.
对于方程组,如果我们把第 i i i个方程当成是一个向量 α i alpha_i αi(这是不严谨的说法),则 α 3 = α 1 + α 2 alpha_3 = alpha_1 + alpha_2 α3=α1+α2,因此第三个方程是多余的.
反之,如果 m 0 β + m 1 α 1 + m 2 α 2 + ⋯ + m k α k = 0 m_0beta + m_1alpha_1 + m_2alpha_2 + cdots + m_kalpha_k = 0 m0β+m1α1+m2α2+⋯+mkαk=0当且仅当 m 0 , m 1 , m 2 , ⋯ , m k m_0, m_1, m_2, cdots, m_k m0,m1,m2,⋯,mk全都为0,则称 β , α 1 , α 2 , ⋯ , α k beta, alpha_1, alpha_2, cdots, alpha_k β,α1,α2,⋯,αk是线性无关的.
判断一个方程组有唯一解我们有两条法则:
- n n n个未知数要有 n n n个方程
- 可以使用线性无关去判断“有效的方程”
如果当一个方程组未知数的量很大之后,需要去判断哪些方程是“有效的”是一件非常花时间的工作,有没有一个更好的方法呢?答案是有的,我们先介绍行列式的概念.矩阵就是一种数表,系数矩阵 A A A总是行数、列数相等的,因为它的方程个数等于未知数的个数,像这样行数等于列数的矩阵我们称为方阵.对于方阵而言,我们可以计算它的行列式 ∣ A ∣ |A| ∣A∣,用Numpy实现如下:
A = np.array([[1, 1, 1],
[2, 4, 2],
[2, 2, 2]])
np.linalg.det(A) # 计算方阵A的行列式
print("A的行列式的值为:",np.linalg.det(A))
B = np.array([[1,1,1,1],
[1,2,0,0],
[1,0,3,0],
[1,0,0,4]])
B_det = np.linalg.det(B)
print("B的行列式的值为:",B_det)
# B = np.array([[1,1,1,1],
# [1,2,0,0],
# [1,0,0,4]])# 你可以尝试用非方阵计算行列式,压根没法算!
注:一定要是方阵才能求行列式!
有了行列式之后,以后只要我们判断了一个方程组:
- 未知数个数等于方程的个数
- 系数行列式
∣
A
∣
≠
0
|A| neq 0
∣A∣=0
则这个方程组是有唯一解的.
上面这个判断的法则就是著名的克莱姆法则(Cramer’s Rule),更重要的是,克莱姆法则提出了一种解的结构:
克莱姆法则
设线性方程组的表达式为:
{
a
11
x
1
+
a
12
x
2
+
⋯
+
a
1
n
x
n
=
b
1
a
21
x
1
+
a
22
x
2
+
⋯
+
a
2
n
x
n
=
b
2
⋯
⋯
a
n
1
x
1
+
a
n
2
x
2
+
⋯
+
a
n
n
x
n
=
b
n
left{begin{array}{c}a_{11} x_{1}+a_{12} x_{2}+cdots+a_{1 n} x_{n}=b_{1} \ a_{21} x_{1}+a_{22} x_{2}+cdots+a_{2 n} x_{n}=b_{2} \ cdots cdots \ a_{n 1} x_{1}+a_{n 2} x_{2}+cdots+a_{n n} x_{n}=b_{n}end{array}right.
⎩⎪⎪⎨⎪⎪⎧a11x1+a12x2+⋯+a1nxn=b1a21x1+a22x2+⋯+a2nxn=b2⋯⋯an1x1+an2x2+⋯+annxn=bn
,系数行列式为:
D
=
∣
a
11
a
12
⋯
a
1
n
a
21
a
22
⋯
a
2
n
⋯
⋯
⋯
⋯
a
n
1
a
n
2
⋯
a
m
n
∣
≠
0
D = left|begin{array}{cccc}a_{11} & a_{12} & cdots & a_{1 n} \ a_{21} & a_{22} & cdots & a_{2 n} \ cdots & cdots & cdots & cdots \ a_{n 1} & a_{n 2} & cdots & a_{m n}end{array}right| neq 0
D=∣∣∣∣∣∣∣∣a11a21⋯an1a12a22⋯an2⋯⋯⋯⋯a1na2n⋯amn∣∣∣∣∣∣∣∣=0,则该线性方程组有且仅有唯一解:
x 1 = D 1 D , x 2 = D 2 D , ⋯ , x n = D n D x_{1}=frac{D_{1}}{D}, x_{2}=frac{D_{2}}{D}, cdots, x_{n}=frac{D_{n}}{D} x1=DD1,x2=DD2,⋯,xn=DDn
其中, D j = ∣ a 11 ⋯ a 1 , j − 1 b 1 a 1 , j + 1 ⋯ a 1 n a 21 ⋯ a 2 , j − 1 b 2 a 2 , j + 1 ⋯ a 2 n ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ a n 1 ⋯ a n , j − 1 b n a n , j + 1 ⋯ a n n ∣ D_{j}=left|begin{array}{ccccccc}a_{11} & cdots & a_{1, j-1} & b_{1} & a_{1, j+1} & cdots & a_{1 n} \ a_{21} & cdots & a_{2, j-1} & b_{2} & a_{2, j+1} & cdots & a_{2 n} \ cdots & cdots & cdots & cdots & cdots & cdots & cdots \ a_{n 1} & cdots & a_{n, j-1} & b_{n} & a_{n, j+1} & cdots & a_{n n}end{array}right| Dj=∣∣∣∣∣∣∣∣a11a21⋯an1⋯⋯⋯⋯a1,j−1a2,j−1⋯an,j−1b1b2⋯bna1,j+1a2,j+1⋯an,j+1⋯⋯⋯⋯a1na2n⋯ann∣∣∣∣∣∣∣∣
2.3 矩阵对于一个矩阵 A A A,假设行数为 n n n,列数为 m m m,则它的维度为 n × m n times m n×m,记作: A n × m A_{ntimes m} An×m. 当两个矩阵要做乘法时,我们要求前一个矩阵的列数要等于后一个矩阵的行数,即:给定 A a × b , B c × d A_{atimes b},B_{c times d} Aa×b,Bc×d,若 A B AB AB有意义,则 b = c b=c b=c,并且结果的维度为 a × d atimes d a×d,结果矩阵的第 i j ij ij个元素为:前一个矩阵的第 i i i个行向量与后一个矩阵第 j j j个列点乘得到. 也正是如此,我们不能对矩阵乘法轻易交换顺序,也就是说 A B AB AB不一定等于 B A BA BA,这个一定要注意!
A = np.array([[1, 2],
[1, -1]])
B = np.array([[1, 2, -3],
[-1, 1, 2]])
print("A的规模{}".format(A.shape))
print("B的规模{}".format(B.shape))
# 计算AB
print("AB=n{}".format(np.matmul(A, B)))
# 计算BA会报错维度不对应
# np.matmul(B, A)
两个维度大小一个矩阵可以做加法,即对应位置元素相加. 一个矩阵乘一个常数等于每个位置的元素都乘这个常数
A = np.array([[1, 2],
[1, -1]])
C = np.array([[1, 2],
[3, 4]])
print("A+C = n", A + C) # A+C
print("3*A = n", 3 * A) # 3*A
特殊的矩阵
- 单位矩阵
在矩阵的乘法中,有一种矩阵起着特殊的作用,如同数的乘法中的1,这种矩阵被称为单位矩阵. 它是个方阵,从左上角到右下角的对角线(称为主对角线)上的元素均为1,除此以外全都为0.
print("B =n", B,"n", "E = n", np.eye(3)) # 3阶单位阵
np.matmul(B, np.eye(3))
- 初等矩阵
如果你想让计算机懂得解方程组的三个步骤,首先我们先抽象出一个方程组的系数矩阵$A_{ntimes m} $,假设下面介绍三个操作对应的矩阵变换,称为初等矩阵. - 逆矩阵
对于 n n n阶方阵 A A A,如果存在一个 n n n阶方阵 B B B,使得
A B = B A = E n AB=BA=E_n AB=BA=En
则我们称 A A A是可逆的, B B B是 A A A的逆矩阵,记做 A − 1 A^{-1} A−1.
如果一个矩阵是可逆的,那么首先它一定要是个方阵,也就是行数等于列数,此外它还要满足行列式不等于0,也就是我们上面提到的非奇异矩阵.我们在此不给出严格的证明,这个可以联想除法去理解,当你要“除”过去,作为“分母”自然不能为0.
至于如何计算,我们可以通过Numpy模块求解:
import numpy as np
A = np.array([[1, 2], [3, 4]])
print(np.linalg.det(A),"行列式不为0,非奇异阵") # 检验是否奇异
print("A的逆矩阵:n", np.linalg.inv(A)) # 矩阵求逆
A_inv = np.linalg.inv(A)
print("验证AA_inv = E n", np.matmul(A, A_inv))
这里看着不像单位阵,但实际上是因为数值计算带来的后果,我们仅需要做一下数值过滤即可.事实上,为了一些应用更加简便,对于非奇异阵我们也定义了"伪逆".
它的定义是这样的:对于任意一个矩阵
A
∈
R
n
×
m
A in mathbb{R}^{ntimes m}
A∈Rn×m,存在一个矩阵
A
g
∈
R
m
×
n
A^g in mathbb{R}^{mtimes n}
Ag∈Rm×n,使得
A
A
g
A
=
A
AA^gA=A
AAgA=A,则称
A
g
A^g
Ag为
A
A
A的伪逆(广义逆).
具体实现如下:
B = np.array([[0, 1],
[0, -1]])
print(np.linalg.det(B),"行列式为0,奇异阵") # 检验是否奇异
# print("B的逆矩阵:n", np.linalg.inv(B)) # 直接求逆会报错
print(np.linalg.pinv(B))
print(np.matmul(np.matmul(B, np.linalg.pinv(B)),B)) # 验证广义逆的定义
(三) 对角化、矩阵的特征值与特征向量、正交化
重要的核心概念:向量在空间中的位置是绝对的,而其坐标值却是相对的,坐标的取值依托于其所选取的坐标向量(基底)
- 相似矩阵
一个向量在空间位置里,选取不同的坐标系,其坐标值是不同的. 对于空间中同一个线性变换,在不同的坐标系下,用于描述这个变换的矩阵也是不同的, 而这些不同矩阵所描述的线性变换是相似的,因此我们称他们为相似矩阵. - 对角矩阵
使得线性变换的矩阵是最佳的
当我们同时需要经历很多次线性变换的时候,对角矩阵能极大的减少我们的计算量
特征值与特征向量
-正交矩阵(*)
令一个向量进行旋转变换或者镜像变换的矩阵



