最近,我正在我的硕士论文中使用一种论文来实现一种算法,但是在执行某些操作所需的时间时遇到了一些问题。
在开始详细介绍之前,我只想补充一下,我的数据集大约包含4kk个数据点条目。
我有两个从框架(annoy)获取的元组列表,该框架计算向量与数据集中其他向量之间的余弦相似度。最终格式如下:
[(name1, cosine), (name2, cosine), ...]
由于算法的原因,我在其中有两个名称相同(元组的第一个值)的列表,但有两个不同的余弦相似度。我要做的是将两个列表中的余弦值相加,然后对数组排序并获得前N个最高的余弦值。
我的问题是:花了太长时间。我对该实现的实际代码如下:
def topN(self, user, session):
upref = self.m2vTN.get_user_preference(user)
spref = self.sm2vTN.get_user_preference(session)
# list of tuples 1
most_su = self.indexer.most_similar(upref, len(self.m2v.wv.vocab))
# list of tuples 2
most_ss = self.indexer.most_similar(spref, len(self.m2v.wv.vocab))
# concat both lists and add into a dict
d = defaultdict(int)
for l, v in (most_ss + most_su):
d[l] += v
# convert the dict into a list, and then sort it
_list = list(d.items())
_list.sort(key=lambda x: x[1], reverse=True)
return [x[0] for x in _list[:self.N]]
如何使此代码更快?我试过使用线程,但是不确定是否会更快。获取列表不是这里的问题,而是串联和排序。
谢谢!英语不是我的母语,所以很抱歉拼写错误。
答案 0 :(得分:0)
“太长”是什么意思?这两个列表有多大?您的模型和中期结果是否有可能大于RAM,从而迫使虚拟内存分页(这将导致令人沮丧的缓慢性)?
如果您实际上在模型中使用所有向量获得了余弦相似度,那么烦恼索引器将无济于事。 (其目的是更快地获取一小部分最近邻,以牺牲完美的准确性为代价。但是,如果您要计算与每个候选者的相似度,则使用ANNOY不会带来任何好处或优势。
此外,如果您要将两个这样的计算中的所有距离进行合并,则无需进行most_similar()
通常会进行的排序-这只会使以后合并值变得更加复杂。对于gensim
向量模型,您可以提供一个虚假的topn
值,以按顺序获取到所有模型向量的未排序距离。然后,您将拥有两个大型的距离数组,它们以模型的相同本机顺序排列,很容易将它们逐元素相加。例如:
udists = self.m2v.most_similar(positive=[upref], topn=False)
sdists = self.m2v.most_similar(positive=[spref], topn=False)
combined_dists = udists + sdists
combined_dists
未标记,但顺序与self.m2v.index2entity
相同。然后,您可以按照类似于most_similar()
方法本身的方式对它们进行排序,以找到排名最接近的。例如,请参见gensim
的那部分的most_similar()
源代码:
最后,您可能根本不需要自己进行此计算。您可以向most_similar()
提供多于一个的向量作为positive
目标,然后它将返回最接近两个向量的平均值的向量。例如:
sims = self.m2v.most_similar(positive=[upref, spref], topn=len(self.m2v))
这与您的其他总和不会是相同的值/等级,但其行为可能非常相似。 (如果您想要的不是所有相似之处,那么也可以以这种方式使用ANNOY indexer
。)