应优先使用sklearn.metrics.pairwise.cosine_similarity,因其底层优化BLAS、自动处理零向量、支持稀疏矩阵、避免手动实现的除零、精度丢失和内存爆炸等问题。

直接用 sklearn.metrics.pairwise.cosine_similarity,别手写循环或自己实现点积除模长——它底层调用优化过的 BLAS,对上万维、数万样本的数据集仍稳定高效。
为什么不用 np.dot(a, b.T) / (np.linalg.norm(a, axis=1)[:, None] * np.linalg.norm(b, axis=1)[None, :])?
手动实现看似可控,但实际踩坑密集:
- 当某行全为 0 时,
np.linalg.norm返回 0,导致除零警告甚至 NaN,而cosine_similarity默认将零向量间的相似度设为 0.0,行为更鲁棒 - 未归一化的输入若含极大值(如稀疏特征经 TF-IDF 后的浮点大数),手动计算易因浮点精度丢失导致结果略大于 1 或小于 -1,后续做阈值过滤(如
sim > 0.9)可能漏判 - 内存占用翻倍:手动广播会生成 shape 为
(n_samples_a, n_samples_b)的中间矩阵,而cosine_similarity在稀疏矩阵输入下可延迟计算、复用缓存
输入是稀疏矩阵(如 scipy.sparse.csr_matrix)时必须注意的三件事
高维文本或用户行为数据常以稀疏格式存储,这时:
- 传入前确保两矩阵 dtype 一致,比如都为
np.float32——cosine_similarity对float64和float32混用不报错但结果有微小偏差 - 如果 A 是
csr_matrix、B 是csc_matrix,函数内部会隐式转换 B 为csr,触发一次完整拷贝;统一转成csr可省下 30%+ 时间 - 不要提前对稀疏矩阵调用
.toarray()—— 一个 10k×100k 的稀疏矩阵转稠密后可能吃光 20GB 内存
批量计算时如何避免 OOM 和慢得离谱?
当 A 有 50 万样本、B 有 2 万样本,直接算会生成 100 亿个相似度值,内存和时间都不现实:
立即学习“Python免费学习笔记(深入)”;
- 改用分块:对 A 按 batch_size=1000 切片,逐批调用
cosine_similarity(A_batch, B),结果拼接即可 - 如果只关心 Top-K(如每个 A 找最相似的 5 个 B),用
sklearn.neighbors.NearestNeighbors(algorithm='brute', metric='cosine')更快,它底层跳过全量计算,用部分排序加速 - 确认是否真需要余弦相似度:若原始数据已 L2 归一化(即每行模长为 1),那么余弦相似度就等于点积,此时用
np.matmul(A, B.T)比调用cosine_similarity快 2–3 倍
高维场景下最容易被忽略的是预处理一致性——训练时用了 TF-IDF + L2 归一化,推理时却忘了对新样本做同样归一化,导致相似度值系统性偏移。别假设“反正都是余弦”,向量长度本身就在影响结果。


















