向量空间、维度和四大子空间
空间的概念
空间是一个集合。
欧几里得空间
欧几里得空间是有序的实数元组的集合,如
(
6
,
66
)
属
于
一
个
二
维
欧
几
里
得
空
间
,
R
2
(6, 66)属于一个二维欧几里得空间,R^2
(6,66)属于一个二维欧几里得空间,R2
(
3.14
,
0
,
2
)
属
于
三
维
欧
几
里
得
空
间
,
R
3
(3.14, 0, \sqrt{2}) 属于三维欧几里得空间,R^3
(3.14,0,2)属于三维欧几里得空间,R3
更通俗的说,欧几里得空间是点集,也可以理解为是起点为原点的向量集合。
向量空间
空间中的元素都是向量,欧几里得空间也是一个向量空间。向量空间中的向量完全可以看做是欧几里得空间中的元组,所以向量空间一般也就意味着是欧几里得空间。总结而言,欧几里得空间是狭义的向量空间。
对于一个向量空间 V V V,具有如下性质
- 如果向量 u ⃗ \vec{u} u和 v ⃗ \vec{v} v都属于 V V V,则 u ⃗ + v ⃗ \vec{u}+\vec{v} u+v属于 V V V。
- 如果向量 u ⃗ \vec{u} u属于 V V V, k k k是一个实数,则 k ⋅ u ⃗ k\cdot\vec{u} k⋅u属于 V V V。
这两条性质在数学上被称为“封闭”
- u ⃗ + v ⃗ = v ⃗ + u ⃗ \vec{u}+\vec{v}=\vec{v}+\vec{u} u+v=v+u
- ( u ⃗ + v ⃗ ) + w ⃗ (\vec{u}+\vec{v})+\vec{w} (u+v)+w = u ⃗ + ( v ⃗ + w ⃗ ) \vec{u}+(\vec{v}+\vec{w}) u+(v+w)
- 存在零向量 O O O属于向量空间,使得 u ⃗ + O = u ⃗ \vec{u}+O=\vec{u} u+O=u
- 对于每一个 u ⃗ \vec{u} u,存在 − u ⃗ -\vec{u} −u,使得 u ⃗ + − u ⃗ = O \vec{u}+-\vec{u}=O u+−u=O
- 数乘结合律: ( k ⋅ c ⃗ ) ⋅ u ⃗ = k ⋅ ( c ⃗ ⋅ u ⃗ ) (k\cdot\vec{c})\cdot\vec{u} = k\cdot(\vec{c}\cdot\vec{u}) (k⋅c)⋅u=k⋅(c⋅u)
- 数乘分配律: k ⋅ ( c ⃗ + u ⃗ ) = k ⋅ c ⃗ + k ⋅ u ⃗ k\cdot(\vec{c}+\vec{u}) = k\cdot\vec{c}+k\cdot\vec{u} k⋅(c+u)=k⋅c+k⋅u
- 数乘分配律: ( k + c ) ⋅ u ⃗ = k ⋅ u ⃗ + c ⋅ u ⃗ (k+c)\cdot\vec{u} = k\cdot\vec{u} + c\cdot\vec{u} (k+c)⋅u=k⋅u+c⋅u,其中k和c是实数
- 1 ⋅ u ⃗ = u ⃗ 1\cdot\vec{u}= \vec{u} 1⋅u=u
这同时也是向量的10个基本性质。
广义向量空间
区别于狭义的向量空间,通常把非欧几里得空间的向量空间称为广义向量空间。如,所有 m × n m×n m×n的矩阵构成的空间就是一个广义线性空间,因为 2 × 2 2×2 2×2的方阵满足加法和数乘的运算,所以 m × n m×n m×n的矩阵构成一个空间。不仅仅是矩阵,所有的多项式也同样是广义的向量空间。
子空间
假设 V V V是一个向量空间,如果 S S S是 V V V的一个子集,且 S S S还是一个向量空间,则称 S S S是 V V V的一个子空间。
如何判断
S
S
S是否是一个向量空间?
遵循上面提及的十条性质的一定是向量空间,但是实际上只需要判断集合中的向量是否符合前两条性质即可,因为后面的都是前两条性质衍生出的性质。即 假设
V
V
V是一个向量空间,如果
S
S
S是
V
V
V的一个子集,且
S
S
S对加法和数量乘法封闭,则称
S
S
S是
V
V
V的一个子空间。
欧几里得空间的子空间
从二维欧几里得空间开始推导,首先还是回顾子空间的判断条件:子空间
S
S
S对向量的加法和数量乘法封闭。二维欧几里得空间的子空间实际上就是一条经过原点的直线,
并不是二维欧几里得空间中所有的直线都是子空间。反例如下,
- 不经过原点的直线
- 经过原点的射线
实际上原点也可以看做是二维欧几里得空间的子空间。
推而广之,到三维及以上的欧几里得空间,
实际上在机器学习的降维算法中就是找到一个高维空间的子空间,这些数据在子空间中也能找到对应的位置,且不会丢失任何信息。
维度
概念
回顾空间的基的概念,空间的基是一组向量,能够生成空间且线性无关。一个空间的基中,向量的个数就称为维度。
子空间和维度
依旧是以二维空间开始进行推导
三维空间
当一个欧几里得空间有
n
n
n个有序实数元组,生成的欧几里得空间不一定是
n
n
n维的。
行空间和矩阵的秩
行空间
矩阵中,行向量生成的空间称为行空间;列向量生成的空间称为列空间。
对于一个 m m m行 n n n列的矩阵而言,其行空间一定是 n n n维空间的子集(因为每行有 n n n个元素);列空间一定是 m m m维空间的子集(每列有 m m m个元素)。
也就是说,行空间的维度一定小于等于 n n n,具体行空间维度的求法可以参考Gauss-Jordan消元法进行求取,如下
Gauss-Jordan消元法的结果的每一行都是原来矩阵各行的线性组合。以下面的例子进行演示,将一个矩阵进行Gauss-Jordan分解,
使用Gauss-Jordan消元法将矩阵变换成行最简形式,非零行的个数即为生成空间的维度。零行表示该行的向量线性相关。
一个矩阵行最简形式的非零行,就是矩阵的各行向量构成的空间的一组基。对于这个性质的证明如下,
行秩
一个矩阵的行最简形式的非零行数量称为矩阵的行秩。即行空间的维度实际上就是矩阵行秩所对应的数字。
这两个概念的区别在于作用的对象是不同的,空间是有维度的,但是没有行秩;矩阵具有行秩,但是没有维度。
列空间与列秩
矩阵中,列向量生成的空间称为列空间。对于一个
m
m
m行
n
n
n列的矩阵而言,其行空间一定是
n
n
n维空间的子集(因为每行有
n
n
n个元素);列空间一定是
m
m
m维空间的子集(每列有
m
m
m个元素)。
对上面的矩阵进行Gauss-Jordan消元法,
需要注意,与行空间不同,主元列对应的原矩阵的列,是列空间的一组基。因为列向量化为行最简形式后,与原矩阵的列是没有关系的。
行空间和列空间对比
矩阵的秩与矩阵的逆
行秩与列秩的关系
矩阵有一个很重要的性质,即矩阵的行秩等于矩阵的列秩。即矩阵的行空间和列空间的维度是相等的。
对上述性质进行证明,对于一个
m
×
n
m×n
m×n的矩阵,对其进行Gauss-Jordan消元操作,
行最简形式中,如果存在零行,其位置一定在矩阵的最下方;如果存在自由列,则同样可以使用一条竖线将主元列和自由列分开,
非零行和主元列构成了一个单位矩阵,一个方阵,所以非零行数等于主元列数,所以对于一个矩阵而言,行秩=列秩。
矩阵的秩
阵的行秩和列秩在任何时候都是相等的,所以对于行秩和列秩而言不用再进行区分,统称为矩阵的秩。
对于一个方阵而言,其行空间是n维空间的子空间,其列空间是n维空间的子空间。当 矩阵的秩=矩阵的行秩 = 矩阵的列秩 = n n n时,矩阵的状态为满秩。此时该方阵的行最简形式一定是一个单位矩阵。
回顾之前矩阵的逆的等价命题,当方阵的行最简形式是一个单位矩阵时,该方阵一定可逆。所以等价命题又多了几个命题,
实现矩阵的秩
行秩和列秩都能求取矩阵的秩,本次使用行秩求取矩阵的秩。继续之前 LinearSystem的基础上继续写代码,
class LinearSystem:
def __init__(self, A, b=None):
assert b is None or A.row_num == len(b)
self._m = A.row_num()
self._n = A.col_num()
if b is None:
self.Ab = [A.row_vector(i) for i in range(self._m)]
if isinstance(b, Vector):
self.Ab = [Vector(A.row_vector(i).underlying_list()+b[i]) for i in range(self._m)]
if isinstance(b, Matrix):
self.Ab = [Vector(A.row_vector(i).underlying_list()+b.row_vector(i).underlying_list() for i in range(self._m)]
......
def inv(A):
"""
求解矩阵的逆
"""
......
def rank(A):
"""
求解矩阵的秩
"""
ls = LinearSystem(A)
ls.gauss_jordan_elimination()
zero = Vector.zero(A.col_num())
return sum([row != zero for ls.Ab])
因为这里判断了两个Vector类对象是否相等,所以需要在之前的Vector类中进行一些改动,
class Vector:
......
def __eq__(self, other):
"""
比较两个向量是否相等
"""
if len(other) != len(self._values):
return False
other_list = other.underlying_list()
return all(x - y <= EPSILON for x, y in zip(self._values, other_list))
def __neq__(self, other):
"""
判断两个Vector对象不等
"""
return not(self==other)