如何高效计算两个数组的余弦相似度并构建相似性矩阵
高效计算余弦相似度矩阵的numpy实现
要替代循环实现高效的余弦相似度计算,直接利用numpy的向量/矩阵运算即可,这比Python循环快几个数量级——因为numpy的底层运算都是C优化的,能充分利用CPU的并行计算能力。
核心思路
余弦相似度的公式为:
$\text{cos_sim}(a, b) = \frac{a \cdot b}{|a|_2 \times |b|_2}$
我们可以把整个计算拆解为三个并行步骤,再通过numpy的广播机制完成逐元素除法:
- 计算所有A行与B行的点积矩阵(对应公式分子)
- 计算A每行的L2范数、B每行的L2范数(对应公式分母)
- 用点积矩阵除以范数的外积,得到最终的相似度矩阵
代码实现
import numpy as np # 示例:初始化符合形状的数组(实际使用替换成你的A和B) A = np.random.rand(20, 200) B = np.random.rand(15, 200) # 1. 计算点积矩阵,形状为(20,15) dot_product = A @ B.T # 2. 计算A的行L2范数并转为列向量(20,1),方便广播 norm_A = np.linalg.norm(A, axis=1, keepdims=True) # 计算B的行L2范数并转为行向量(1,15) norm_B = np.linalg.norm(B, axis=1, keepdims=True).T # 3. 计算余弦相似度矩阵,添加小epsilon避免除以0的情况 epsilon = 1e-10 C = dot_product / (norm_A * norm_B + epsilon) # 最终C的形状为(20,15),c[i,j]即A[i]与B[j]的余弦相似度
效率优势说明
- Python循环是逐元素解释执行,而numpy的矩阵运算会把整个操作批量交给底层的BLAS/LAPACK库处理,这些库用高度优化的C/汇编实现,能充分利用CPU的多线程和向量指令集(如AVX)。
- 广播机制避免了显式的循环嵌套,既简化了代码,又减少了Python层的运算开销。
如果后续数组规模继续增大(比如百万级样本),还可以考虑faiss这类专门的相似度计算库,但对于当前规模,numpy完全能满足高效计算的需求。
内容的提问来源于stack exchange,提问作者phantrang
相关产品推荐
相关产品推荐

