壁纸来源 · MotionBGS
1010 字
5 分钟
09 L2 norm 与 cosine similarity
M2.3 向量长度连接 M2.2 方向相似度。正文是复习提纲;文末为学生当前代码快照,不是完整模块掌握证明。
1. 长度与方向分开看
向量像一支从原点出发的箭头。L2 norm 是箭头的长度,即终点到原点的欧氏距离;不是各分量直接相加。点积同时受长度和方向影响,只把箭头拉长也可能使点积变大。
x (D,) → 平方、求和、开平方 → 长度 ()非零 x → 除以自身长度 → 单位向量 (D,)两个单位向量 → 点积 → cosine similarity ()非零向量的单位化保留方向,把长度变为 1(原本是单位向量则不变):
2. 用归一化点积比较方向
要求两个向量非零、维度相同。除以长度乘积是为了去掉长度对点积的影响,不只是把数值压进一个区间;结果是夹角余弦,位于 [-1,1],不是概率。
| 值 | 几何含义 |
|---|---|
| 1 | 同方向 |
| 0 | 垂直 |
| -1 | 反方向 |
本课一组例子:u=(3,4)、v=(6,8)、z=(-3,-4),长度为 5、10、5。
u 与 v 的 cosine 为 1,u 与 z 为 -1。三个单位向量长度相同,不意味着分量符号或方向相同。
3. 缩放与零向量
只缩放 a:正数倍不改变 cosine;负数倍让结果取相反数(原来为 0 仍为 0)。只有 a 的长度被缩放,b 的长度不变。
- 零向量的 L2 norm 合法且为 0;但没有确定方向,标准 cosine 公式的分母为 0。
- 本练习对 cosine 的零向量输入抛
ValueError,不静默返回 0。一些库会约定零向量输出值,不等于数学公式在该点有定义。 - Python 中要写完整分母括号:
dot / (norm_a * norm_b),不是dot / norm_a * norm_b。
4. 接口与测试边界
- 本练习输入约定:非空、一维实数数组;cosine 两个输入还须等长且非零。
l2_norm自己检查一维、非空;不能只依赖上层 cosine 的检查。- 空数组
[]不等于零向量[0,0],异常信息要匹配条件。 - 每个测试单独捕获预期异常,异常后再跑正常用例,验证控制流继续。
- 当前代码是打印式检查,尚未将预期值写成自动断言;普通数值通过不保证极大 / 极小值或非有限输入的稳定性,这些本课未评估。
来源:scikit-learn cosine_similarity 的 normalized dot product 定义,本课教师已核对;NumPy linalg.norm 本课抓取超时,未声称成功查阅。L2 norm 的勾股直觉与缩放推导为教师补讲;无学生阅读证明。
上一课:08 点积。
附录:学生代码快照
以下为学生当前已保存的实现,仅供复习,不是教师参考答案或独立掌握证明。原练习文件是唯一编辑源;快照不会自动同步,原文件修改后需重新生成。
cosine_check.py
'''Author: Wang-nine Wang-nine@users.noreply.github.comDate: 2026-11-11 11:55:02LastEditors: Wang-nine Wang-nine@users.noreply.github.comLastEditTime: 2026-11-11 14:54:22Description: justing learning!'''import numpy as np
def main(): test_cosine_similarity(np.array([]), np.array([])) test_cosine_similarity(np.array([3, 4]), np.array([3])) test_cosine_similarity(np.array([[3], [4]]), np.array([3, 4])) test_cosine_similarity(np.array([0, 0]), np.array([3, 4])) test_l2_norm(np.array([])) test_l2_norm(np.array([[3], [4]])) test_l2_norm(np.array([0, 0])) test_cosine_similarity(np.array([3, 4]), np.array([6, 8])) test_cosine_similarity(np.array([3, 4]), np.array([-3, -4])) test_cosine_similarity(np.array([1, 0]), np.array([0, 2])) test_cosine_similarity(np.array([1, 0]), np.array([1, 1])) test_cosine_similarity(np.array([0, 0]), np.array([1, 1]))
def test_l2_norm(x: np.ndarray) -> None: try: print(f"the l2 norm of x is {l2_norm(x)}") except ValueError as e: print(e)
def test_cosine_similarity(a: np.ndarray, b: np.ndarray) -> None: try: print(f"the cosine similarity of {a} and {b} is {cosine_similarity(a, b)}") except ValueError as e: print(e)
def l2_norm(x: np.ndarray) -> float: if x.ndim != 1: raise ValueError("pls make sure the array's just have one dimension!") if x.size == 0: raise ValueError("pls make sure the vector is not empty!") return np.sum(x * x) ** 0.5
def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float: #verify the vector is valid if a.ndim != 1 or b.ndim != 1: raise ValueError("pls make sure the array's just have one dimension!") elif a.size == 0 or b.size == 0: raise ValueError("pls make sure the vector is not empty!") elif a.size != b.size: raise ValueError("pls check the size of a be have the same size of b!") elif np.all(a == 0) or np.all(b == 0): raise ValueError("pls make sure that array can not filled with zeros!") #calculate the cosine similarity return (a @ b) / (l2_norm(a) * l2_norm(b))
if __name__ == "__main__": main()本文于2026-11-12整理公开,日期为导入日期。