3E7 x 3E7
是荒谬矩阵大小。在低性能笔记本电脑/台式机上实现这一目标的唯一方法是使用生成器来减少内存占用,并将问题细分为效率问题。
以下函数使用的发电机厂,并使用双for
遍历组块的笛卡尔乘积。我们预先计算语料库中每个tfidf
的规范。
这不是设计为较小的数据这样做同样的任务最快的解决方案。这是为了在一台适度的机器的内存中完成这项任务。
from scipy.sparse import coo_matrix
import numpy as np
def f(t, c, p=-1, v=False):
n = (t ** 2).sum(1) ** .5
g = lambda: ((x, t[x:x+c]) for x in range(0, t.shape[0], c))
h = lambda a, b, i, j: a.dot(b.T)/n[i:i+c, None]/n[j:j+c]
d = lambda s: (s * (1 - np.eye(s.shape[0])))
for i, a in g():
for j, b in g():
s = h(a, b, i, j)
if i == j:
s = d(s)
i_, j_ = np.where(s > p)
if v:
print('\r', 'i = {:0000000d}; j = {:0000000d}'.format(i, j), end='')
yield s[i_, j_], i_ + i, j_ + j
有了,我们通过计算它们自己在每个分块和跟踪的相似之处比我们的阈值提取余弦相似。
最后,我们通过足够的相似用的相似的坐标以一个稀疏矩阵构造,并将结果指定到名称m
。如果您需要矩阵表示,请使用m.toarray()
。
values, *ij = zip(*f(tfidf_matrix, 5000, .8, v=True))
values = np.concatenate(values)
ij = list(map(np.concatenate, ij))
m = coo_matrix((values, ij))
请注意,我零对角线。否则,如果我们使用阈值-1
,这将产生与sklearn.metrics.pairwise
中的cosine_similarity
完全相同的内容。
相同的烦躁的验证
from sklearn.metrics.pairwise import cosine_similarity
tfidf_matrix = np.random.randint(10, size=(1000, 100))
s = cosine_similarity(tfidf_matrix)
values, *ij = zip(*f(tfidf_matrix, 5000, -1, v=True))
values = np.concatenate(values)
ij = list(map(np.concatenate, ij))
m = coo_matrix((values, ij))
# This should be equal the 1000. The number of 1's in the diagonal.
(s - m.toarray()).sum()
1000.0
cosine_similarity将输出一个方阵并且它可能的是在单个列中的一个值是> 0.65和其它的是以下。那么在那种情况下,您希望该列出现在数据框中? –
@VivekKumar好问题。我希望数据框的所有值都堆叠在一起。即数据帧中的每一行应该只有一个相似度分数和相应的文档ID。 'similar_values = similarity_values.stack()。reset_index()。rename(columns = {'level_0':'ID1','level_1':'ID2',0:'Score'})' – Minu