<p>最直接方法是np.linalg.norm(B - a, axis=1):利用广播自动扩展单点a与多点矩阵B相减,再沿特征维(axis=1)求L2范数,高效且内存友好,避免手写平方和开方或临时数组爆炸。</p>

用 numpy.linalg.norm 计算单点到多点距离最直接
多数人想算一个点到一组点的距离,比如聚类中求样本到各簇心的距离。这时候别手写平方和开方,numpy.linalg.norm 底层调用 BLAS,向量化效率高,且自动处理广播。
常见错误是先做 np.sqrt(np.sum((a - b) ** 2, axis=1)) —— 看似清晰,但临时数组多、内存压力大,尤其当 b 是 (N, D) 大矩阵时,(a - b) 会触发隐式广播生成 (N, D) 中间数组,容易 OOM。
正确做法是让 norm 直接处理差值:
import numpy as np a = np.array([1.0, 2.0]) # shape (2,) B = np.random.rand(10000, 2) # shape (10000, 2) dists = np.linalg.norm(B - a, axis=1) # 自动广播,axis=1 沿特征维求范数
注意:axis=1 表示对每个点的坐标差求 L2 范数;若漏掉 axis,会返回整个矩阵的 Frobenius 范数(标量),不是你想要的。
立即学习“Python免费学习笔记(深入)”;
批量计算两组点之间所有配对距离用 scipy.spatial.distance.cdist
如果要算 A 中每个点到 B 中每个点的距离(即输出 (M, N) 距离矩阵),纯 NumPy 写法容易写出三重循环或低效广播(如 np.sqrt(((A[:, None] - B[None, :])**2).sum(2))),内存爆炸且慢。
scipy.spatial.distance.cdist 是专为此设计的:底层 C 实现、支持多种度量、内存友好、可选 metric='euclidean'(默认)。
使用要点:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
-
A和B必须是二维数组,shape 分别为 (M, D) 和 (N, D),不能是 (M,) 或 (N,);一维点需用reshape(-1, D) - 不推荐用
cdist(A, A)算自距离矩阵——它不跳过对角线,且未优化对称性;真需要自距离,用scipy.spatial.distance.pdist+squareform - 若环境不允许引入 SciPy,可用
sklearn.metrics.pairwise.euclidean_distances替代,行为类似但默认不计算平方根(返回平方距离),需手动np.sqrt
避免 np.dot 手推公式时的广播陷阱
有人用恒等式 ||a−b||² = ||a||² + ||b||² − 2⟨a,b⟩ 加速,配合 np.dot 实现,这在理论上能减少一次开方、利于缓存,但极易出错:
典型错误是写成 np.dot(a, B.T) 却忽略 a 是一维时 np.dot 的行为异常(返回标量而非向量),或 B 是 (N, D) 时 B.T 是 (D, N),np.dot(a, B.T) 结果是 (N,),看似对,但若 a 是 (1, D) 就变成 (1, N),后续广播错位。
安全写法是统一用 @ 运算符或 np.matmul,并显式控制维度:
a_sq = np.sum(a**2) B_sq = np.sum(B**2, axis=1) # shape (N,) dot_term = B @ a # shape (N,), 不要用 np.dot(a, B.T) dists_sq = a_sq + B_sq - 2 * dot_term dists = np.sqrt(dists_sq)
注意:B @ a 要求 a 是 1D 或 (D,),若 a 是 (D, 1),得写 B @ a.ravel(),否则报错。
小数据量别硬套向量化,Python 循环有时更快
当点数少于 100,且只算几次距离时,NumPy 启动开销(如创建临时数组、函数调用、类型检查)可能超过纯 Python math.hypot 或简单 for 循环。
实测(i7-11800H,Python 3.11,NumPy 1.26):
- 10 个点以内:纯 Python
[math.hypot(x-a, y-b) for x,y in points]比np.linalg.norm快 2–3 倍 - 100 点以上:NumPy 开始明显占优
- 关键不是“是否用 NumPy”,而是“是否值得为这点数据引入数组转换成本”——比如你已有原生 Python 列表,又只算一次,转
np.array再算,再转回 list,纯属负优化
真正影响性能的,往往不是算法本身,而是数据如何进来、结果如何出去。频繁在 list ↔ ndarray 之间转换,比距离计算本身更耗时。

















