有没有办法进一步优化Python的heapq.nlargest来选择前N项?
Is there any way to further optimize Python's heapq.nlargest for selecting top N items?
我使用 heapq.nlargest
到 select 前 N 个项目,它占用了 98% 运行 的时间(见第 51 行):
Line # Hits Time Per Hit % Time Line Contents
==============================================================
40 @profile
41 def gen_submit(index_to_pri, index_to_sec, exclude_set, pri_mat, sec_mat, gen_count):
42 1 33 33.0 0.0 print('gen_submit')
43 1 87 87.0 0.0 f = open('../submission.txt', 'w')
44 16 28 1.8 0.0 for i, pri in enumerate(index_to_pri):
45 16 369 23.1 0.0 print('generate recommendation for %d-th primary object' % i)
46 16 103 6.4 0.0 recommend_sec = []
47 16 25 1.6 0.0 exclude = exclude_set[pri]
48 16 68215 4263.4 1.3 rating_vector = numpy.dot(pri_mat[i], sec_mat.T)
49 # extract top N
50 16 102 6.4 0.0 N = 500 + len(exclude_set[pri])
51 16 4988735 311795.9 98.2 top_N_indexed_rating = heapq.nlargest(N, enumerate(rating_vector), key = lambda x: x[1]))
52 15 181 12.1 0.0 top_N_j = map(lambda x: x[0], top_N_indexed_rating)
53 7501 6229 0.8 0.1 for j in top_N_j:
54 7501 4812 0.6 0.1 if not index_to_sec[j] in exclude:
55 7500 6135 0.8 0.1 recommend_sec.append(str(j))
56 7500 4943 0.7 0.1 if len(recommend_sec) >= 500: break
57 15 293 19.5 0.0 f.write(' '.join(recommend_sec) + '\n')
58 f.close()
如何进一步优化这个单一操作?
新答案
如果您不需要在 top_N_j
内订购,请尝试
top_N_j = rating_vector.argpartition(len(rating_vector) - N)[-N:]
否则之后用
排序
top_N_j = top_N_j[numpy.argsort(rating_vector[top_N_j])]
我认为这比你给的时间少了大约 30 到 50 倍。
旧答案
我想这太明显了,我可能完全忽略了这一点,但是
heapq.nlargest(N, enumerate(...))
将只取最后的 N
个元素,以相反的顺序标记它们的索引。然后你只能将它用于
top_N_j = map(lambda x: x[0], top_N_indexed_rating)
单独将其转化为索引。
看来你想要的是
end = len(...)
start = max(0, end - N)
top_N_j = reversed(range(start, end))
(尽管我必须承认 非常 对你所做的感到困惑。)
我使用 heapq.nlargest
到 select 前 N 个项目,它占用了 98% 运行 的时间(见第 51 行):
Line # Hits Time Per Hit % Time Line Contents
==============================================================
40 @profile
41 def gen_submit(index_to_pri, index_to_sec, exclude_set, pri_mat, sec_mat, gen_count):
42 1 33 33.0 0.0 print('gen_submit')
43 1 87 87.0 0.0 f = open('../submission.txt', 'w')
44 16 28 1.8 0.0 for i, pri in enumerate(index_to_pri):
45 16 369 23.1 0.0 print('generate recommendation for %d-th primary object' % i)
46 16 103 6.4 0.0 recommend_sec = []
47 16 25 1.6 0.0 exclude = exclude_set[pri]
48 16 68215 4263.4 1.3 rating_vector = numpy.dot(pri_mat[i], sec_mat.T)
49 # extract top N
50 16 102 6.4 0.0 N = 500 + len(exclude_set[pri])
51 16 4988735 311795.9 98.2 top_N_indexed_rating = heapq.nlargest(N, enumerate(rating_vector), key = lambda x: x[1]))
52 15 181 12.1 0.0 top_N_j = map(lambda x: x[0], top_N_indexed_rating)
53 7501 6229 0.8 0.1 for j in top_N_j:
54 7501 4812 0.6 0.1 if not index_to_sec[j] in exclude:
55 7500 6135 0.8 0.1 recommend_sec.append(str(j))
56 7500 4943 0.7 0.1 if len(recommend_sec) >= 500: break
57 15 293 19.5 0.0 f.write(' '.join(recommend_sec) + '\n')
58 f.close()
如何进一步优化这个单一操作?
新答案
如果您不需要在 top_N_j
内订购,请尝试
top_N_j = rating_vector.argpartition(len(rating_vector) - N)[-N:]
否则之后用
排序top_N_j = top_N_j[numpy.argsort(rating_vector[top_N_j])]
我认为这比你给的时间少了大约 30 到 50 倍。
旧答案
我想这太明显了,我可能完全忽略了这一点,但是
heapq.nlargest(N, enumerate(...))
将只取最后的 N
个元素,以相反的顺序标记它们的索引。然后你只能将它用于
top_N_j = map(lambda x: x[0], top_N_indexed_rating)
单独将其转化为索引。
看来你想要的是
end = len(...)
start = max(0, end - N)
top_N_j = reversed(range(start, end))
(尽管我必须承认 非常 对你所做的感到困惑。)