如何并行化scipy余弦相似度计算

时间:2015-03-15 17:28:47

标签: python multithreading scipy multiprocessing cosine-similarity

我通过读取目录中的大量文件来生成大型数据框。我设法并行化了解析文件的部分。我获取该数据并为下一步生成数据帧。这是计算相似度矩阵。

现在,我正在尝试计算数据帧行之间的余弦相似度。由于它是一个大型数据框,因此需要很长时间(小时)才能运行。如何并行化此过程。

这是我目前计算在单线程上运行的余弦相似度的代码:

df = df.fillna(0)

data = df.values
m, k = data.shape

mat = np.zeros((m, m))

"""
scipy cosine similarity is between 0-2 instead of -1 to 1 
in that case 1 is 0 and 2 is -1
"""
for i in xrange(m):
    for j in xrange(m):
        if i != j:
            mat[i][j] = 1 - cosine(data[i,:], data[j,:])
        else:
            mat[i][j] = 1. # 0 if we don't do 1-cosine()

2 个答案:

答案 0 :(得分:1)

首先,我假设您的cosinescipy.spatial.distance.cosine,其关键计算是:

dist = 1.0 - np.dot(u, v) / (norm(u) * norm(v))

所以看起来我可以用:

替换你的双循环
data1 = data/np.linalg.norm(data,axis=1)[:,None]
mat1 = np.einsum('ik,jk->ij', data1, data1)

即,在开始时将data标准化一次,而不是在每个节点处标准化。然后使用einsum计算整套dot产品。

对于小测试用例(m,k = 4,3),这比双循环快25倍。

警告:我只测试了一个小data数组的答案。

scipy.spactial.distance.normcosine有一些我尚未实施的检查。

einsum虽然在适度大小的数组上快速处理这类事情,但是可能会遇到较大的数组,并且会在元素dot之前遇到内存错误。并且可以更好地调整底层dot库以处理多核机器。

但即使data过大而无法通过调用einsum来处理,也可以将计算分解为块,例如

mat[n1:n2,m1:m2] = np.einsum('ik,jk->ij', data1[n1:n2,:], data1[m1:m2,:])

答案 1 :(得分:0)

我想指出你https://docs.python.org/2/library/multiprocessing.html

的方向

记下pool.map(函数,可迭代)

然后构建一组三角形位置元组,编写相应的函数并消失。