如何计算两个csr_matrix间的余弦相似度,有无更优实现方法?
两个CSR矩阵批量计算余弦相似度的优化方案
你当前将稀疏矩阵转为带零值的完整稠密向量的方案,在特征维度高、矩阵规模大的场景下会存在严重的内存浪费,甚至触发内存溢出,完全可以用稀疏矩阵原生运算实现,不需要展开零值,常见可实现方案如下:
- 方案1:原生稀疏矩阵运算实现(精确计算,性能最优)
余弦相似度的核心公式可拆解为:sim(u, v) = 点积(u, v) / (u的L2范数 * v的L2范数),归一化后的向量点积就是余弦相似度,全程可以用稀疏运算完成:- 分别对两个矩阵的所有行做L2归一化,得到归一化后的稀疏矩阵
- 直接计算两个矩阵的转置乘积,结果矩阵的第i行第j列就是第一个矩阵第i个向量和第二个矩阵第j个向量的余弦相似度
示例代码:
from sklearn.preprocessing import normalize # 假设mat1为第一个csr矩阵(形状M*D),mat2为第二个csr矩阵(形状N*D) mat1_norm = normalize(mat1, norm='l2', axis=1) mat2_norm = normalize(mat2, norm='l2', axis=1) # 矩阵乘法全程稀疏运算,不会展开零值 cos_sim_matrix = mat1_norm @ mat2_norm.T # 如需稠密格式结果可调用.toarray(),规模大时建议保留稀疏格式减少内存占用 - 方案2:调用现成封装接口(小数据集适用,代码最简)
scikit-learn的cosine_similarity接口原生支持稀疏矩阵输入,内部已经做了运算优化,不需要手动转稠密:from sklearn.metrics.pairwise import cosine_similarity cos_sim_matrix = cosine_similarity(mat1, mat2) - 方案3:近似检索方案(超大规模数据集适用,牺牲少量精度换性能)
如果你不需要完全精确的相似度结果,仅需要取每个向量的TopK相似结果,且两个矩阵的行数都达到十万以上级别,可以用FAISS、Annoy等近似最近邻库,先对第二个矩阵的向量构建索引,再批量查询第一个矩阵的向量,时间复杂度可从O(MN)降到O(MlogN)。
内容的提问来源于stack exchange,提问作者majid bhatti
相关产品推荐
相关产品推荐

