【问题标题】:How to Parallelized scipy cosine similarity calculation如何并行化 scipy 余弦相似度计算
【发布时间】:2015-05-17 19:14:08
【问题描述】:

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

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

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

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()

【问题讨论】:

  • 你试过squareform(pdist(data, 'cosine'))了吗?同样来自scipy.spatial.distance。它应该比双 for 循环快很多。
  • cosine这个是:scipy.spatial.distance.cosine吗?
  • @hpaulj 是的,我正在使用scipy.spatial.distance.cosine,您认为sklearn 更好吗?

标签: python multithreading scipy multiprocessing cosine-similarity


【解决方案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,:])

【讨论】:

  • 有机会进行聊天吗?我还有一个问题?
  • 我很乐意这样做。你知道怎么设置吗?
  • 不是问题 :) 我找到了聊天的地方chat.stackoverflow.com/?tab=all&sort=people
  • 我想知道当线程变长时系统做了什么
  • 看起来仍然需要很长时间。我会尝试你的第二种方法,它分为两部分。
【解决方案2】:

我想给你指点https://docs.python.org/2/library/multiprocessing.html的方向

注意 pool.map(function, iterable)

然后构建三角位置元组的集合,编写适当的函数并启动。

【讨论】:

    猜你喜欢
    • 2020-08-12
    • 2015-05-24
    • 2019-04-07
    • 2017-01-18
    • 2018-10-02
    • 2017-07-07
    • 2018-04-11
    • 2012-11-20
    相关资源
    最近更新 更多