向量的长度
向量的模
向量的长度也叫向量的模,线性代数中常使用 ||u|| 两个双竖线括起。向量的模求取的方式为 ∣ ∣ u ⃗ ∣ ∣ ||\vec{u}|| ∣∣u∣∣,向量的模的求取方式为,
假设存在一个向量 u ⃗ \vec{u} u
u ⃗ = ( u 1 , u 2 , . . . , u n ) T \vec{u}=(u_1, u_2,...,un)^T u=(u1,u2,...,un)T
其模长为
∣ ∣ u ⃗ ∣ ∣ = u 1 2 + u 2 2 + . . . + u n 2 ||\vec{u}|| =\sqrt{u_1^2+u_2^2+...+u_n^2} ∣∣u∣∣=u12+u22+...+un2
实现求取向量的模
接向量基础一节的代码,
def norm(self):
"""返回向量的模长"""
return math.sqrt(sum(e**2 for e in self))
单位向量
概念
单位向量的模长为1,每个向量都对应存在一个单位向量与其指向的方向相同,
u
⃗
=
(
u
1
,
u
2
,
.
.
.
,
u
n
)
T
\vec{u}=(u_1, u_2,...,un)^T
u=(u1,u2,...,un)T
u
^
=
1
∣
∣
u
⃗
∣
∣
⋅
u
⃗
=
(
u
1
∣
∣
u
⃗
∣
∣
+
u
2
∣
∣
u
⃗
∣
∣
+
.
.
.
+
u
n
∣
∣
u
⃗
∣
∣
)
\hat{u} = \frac{1}{||\vec{u}||}\cdot\vec{u}=(\frac{u_1}{||\vec{u}||}+\frac{u_2}{||\vec{u}||}+...+\frac{u_n}{||\vec{u}||})
u^=∣∣u∣∣1⋅u=(∣∣u∣∣u1+∣∣u∣∣u2+...+∣∣u∣∣un)
这一过程可以看做是在每一个维度上进行标准化的操作,单位向量只表示方向。只由n-1个0和1个1组成的单位向量称为标准单位向量,指向坐标轴正方向的向量。
单位向量实现
def normalize(self):
"""返回当前向量对应的单位向量"""
# 这样写的好处是浮点数之间使用下面的判断方式 if self.norm() == 0 有时会出现较大误差
if self.norm() < EPSILON:
raise ZeroDivisionError("Normalize error. norm is zero")
return Vector([self._values.copy()) / self.norm()
上面的代码中变量"EPSILON"是定义在 _global.py 中的变量,
# -*- coding:utf-8 -*-
EPSILON = 1e-8
向量的点乘(内积)
概念
点乘是向量之间的乘法,
u
⃗
⋅
v
⃗
=
(
u
1
u
2
.
.
.
u
n
)
⋅
(
v
1
v
2
.
.
.
v
n
)
=
u
1
⋅
v
1
+
u
2
⋅
v
2
+
.
.
.
+
u
n
⋅
v
n
=
∣
∣
u
⃗
∣
∣
⋅
∣
∣
v
⃗
∣
∣
⋅
c
o
s
θ
\vec{u}\cdot\vec{v}=\begin{pmatrix}u_1\\u_2\\...\\u_n\end{pmatrix}\cdot\begin{pmatrix}v_1\\v_2\\...\\v_n\end{pmatrix}=u_1\cdot v_1+u_2\cdot v_2+...+u_n\cdot v_n=||\vec{u}||\cdot||\vec{v}||\cdot cos\theta
u⋅v=⎝⎜⎜⎛u1u2...un⎠⎟⎟⎞⋅⎝⎜⎜⎛v1v2...vn⎠⎟⎟⎞=u1⋅v1+u2⋅v2+...+un⋅vn=∣∣u∣∣⋅∣∣v∣∣⋅cosθ
可见,两个向量点乘的结果是一个数(一个标量)。θ是两个向量之间的夹角。
对上面的结论进行证明,以二维空间的向量为例,
证
明
:
u
⃗
⋅
v
⃗
=
∣
∣
u
⃗
∣
∣
⋅
∣
∣
v
⃗
∣
∣
⋅
c
o
s
θ
证明:\vec{u}\cdot\vec{v}=||\vec{u}||\cdot||\vec{v}||\cdot cos\theta
证明:u⋅v=∣∣u∣∣⋅∣∣v∣∣⋅cosθ,此处以二维向量为例,
∣
∣
u
⃗
−
v
⃗
∣
∣
2
=
∣
∣
u
⃗
∣
∣
2
+
∣
∣
v
⃗
∣
∣
2
−
2
∣
∣
u
⃗
∣
∣
⋅
∣
∣
v
⃗
∣
∣
⋅
c
o
s
θ
||\vec{u}-\vec{v}||^2=||\vec{u}||^2+||\vec{v}||^2-2||\vec{u}||\cdot||\vec{v}||\cdot cos\theta
∣∣u−v∣∣2=∣∣u∣∣2+∣∣v∣∣2−2∣∣u∣∣⋅∣∣v∣∣⋅cosθ
∣
∣
u
⃗
∣
∣
⋅
∣
∣
v
⃗
∣
∣
⋅
c
o
s
θ
=
1
2
(
∣
∣
u
⃗
∣
∣
2
+
∣
∣
v
⃗
∣
∣
2
−
∣
∣
u
⃗
−
v
⃗
∣
∣
2
)
=
1
2
(
u
1
2
+
u
2
2
+
v
1
2
+
v
2
2
−
(
u
1
−
u
2
)
2
−
(
v
1
−
v
2
)
2
)
=
u
1
u
2
+
v
1
v
2
||\vec{u}||\cdot||\vec{v}||\cdot cos\theta=\frac{1}{2}(||\vec{u}||^2+||\vec{v}||^2-||\vec{u}-\vec{v}||^2) =\frac{1}{2}(u_1^2+u_2^2+v_1^2+v_2^2-(u_1-u_2)^2-(v_1-v_2)^2)=u_1u_2+v_1v_2
∣∣u∣∣⋅∣∣v∣∣⋅cosθ=21(∣∣u∣∣2+∣∣v∣∣2−∣∣u−v∣∣2)=21(u12+u22+v12+v22−(u1−u2)2−(v1−v2)2)=u1u2+v1v2
有了二维空间的证明,该定理也可以拓展到n维空间中。
代码实现
def dot(self, another):
"""向量点乘,返回一个标量"""
assert len(self) == len(another)
return sum(a * b for a, b in zip(self, another))
在一些数学库中(如numpy),两个向量u和v之间使用“*”相连表示的是向量逐个元素相乘而并非点乘,
u ∗ v = ( u 1 , u 2 , . . . , u n ) T ∗ ( v 1 , v 2 , . . . , v n ) T = ( u 1 ∗ v 1 , u 2 ∗ v 2 , . . . , u n ∗ v n ) T u * v = (u_1,u_2,...,u_n)^T * (v_1,v_2,...,v_n)^T = (u_1*v_1, u_2*v_2,..., u_n*v_n)^T u∗v=(u1,u2,...,un)T∗(v1,v2,...,vn)T=(u1∗v1,u2∗v2,...,un∗vn)T
称为element-wise multiple,但是这个计算不具备数学含义。
点乘的应用
- 几何学应用
反向求取出两个向量之间夹角的余弦值。特别地,如果两个向量夹角为90°,则两个向量点乘的值为0。这个定理反过来也是成立的,如果两个向量点成为0,则二者垂直。如果两个向量点乘不为0,
u * v > 0, 两个向量夹角为锐角
u * v < 0, 两个向量夹角为钝角
u * v = 0, 两个向量相互垂直
- 推荐系统中的应用
这一点判断两个向量的相似程度,在推荐系统中应用比较广泛。值越大越相似,越小越背离。
Numpy中的向量
相比于Python的列表,numpy向量对象只能存储一种类型的元素,这使得运算速度大大加快。
numpy的向量操作是很完善的,常用向量操作,
import numpy as np
if __name__ == "__main__":
# 创建向量
vec = np.array([1, 2, 3])
zero5 = np.zeros(5) # 创建1×5维度的零向量
one5 = np.ones(5)
f5 = np.full(5,3) # 创建1×5维度的元素全部为3的向量
# 向量维度
size = vec.size
# 向量运算
vec2 = np.array([4, 5, 6])
print(vec + vec2) # 返回 [5, 7, 9]
print(2 * vec) # 返回 [2, 4, 6]
print(vec * vec2) # 返回 [4, 10, 18], element-wise乘法
print(np.dot(vec, vec2)) # 返回 32
# 求模和单位向量
print(np.linalg.norm(vec)) # 返回 3.74...
print(vec / np.linalg.norm(vec))
更多如Matrix类,可以见numpy笔记本。