【问题标题】:efficient algorithm for comparing two lists比较两个列表的有效算法
【发布时间】:2021-01-02 22:26:12
【问题描述】:

我正在构建一个项目列表的相似性矩阵。 天真的方法是迭代列表两次,但这会不必要地比较 A:B B:A 当它们相同时。

for A in items:
   for B in items:
      if A==B: continue
      sim[A][B] = calc_sim(A, B)

有没有一种简单的方法来只计算一半的值? 我可以在里面放一个skip

if sim[B][A]: continue # already calculated in other direction

但迭代仍在发生。 实际上,我只想遍历网格的上半部分或下半部分:

有一些similar Qs,但没有一个规范的答案。 这似乎是一个基本的 CS 算法问题!

【问题讨论】:

  • 这是关于 Python 的吗?
  • 以上是伪代码。在这种情况下,我正在编写 python,但它更多的是关于独立于算法语言的。我知道我可以将 sklearn 之类的库用于 NearestNeighbot,但我对自己的原始算法更感兴趣。无论如何添加了一个python标签
  • 使用break 代替continue?
  • @superbrain 我认为你可能是对的!最简单的就是最好的哈哈。

标签: python algorithm sorting matrix sentence-similarity


【解决方案1】:

你可以使用itertools.combinations

import itertools

for a, b in itertools.combinations(items, 2):
    sim[a][b] = sim[b][a] = calc_sim(a, b)

【讨论】:

  • 哦,感谢您指出这一点。它有点特定于 python,但 itertools 是一个很棒的工具箱。
【解决方案2】:

如果你只需要一个通用算法来减少迭代次数,你可以限制内循环的范围

for i, A in enumerate(items):
   for B in items[:i]:
      sim[A][B] = calc_sim(A, B)

但是,如果您正在寻找特定于 Python 的优化,那么使用 numpy 向量化会更好。例如,如果calc_sim(a, b) 计算ab 之间的平方差,则可以通过以下方式对其进行矢量化:

import numpy as np

list = [1, 2, 3]
array = np.array(list)
sim = np.square(array[:,np.newaxis] - array)
[[0 1 4]
 [1 0 1]
 [4 1 0]]

【讨论】:

  • 它实际上是我用来进行比较的词向量数组。可以使np 采用任何比较函数并以这种方式将其应用于网格,或者只是像np.square 这样的np 内置函数?
  • @dcsan 如果向量具有相同的长度,则可以这样做。我认为这个问题可能会有所帮助:stackoverflow.com/questions/35215161/… 但是如果向量具有不同的长度,那么 numpy 不太可能能够处理它们,只要它们没有以某种方式进行预处理
【解决方案3】:

假设calc_sim(A, B) == calc_sim(B, A),你可以试试这个:

for A in range(0, len(items)):
   for B in range(A, len(items)): # Replace with A+1 if you don't want the case A == B
      # Remember A and B are indexes, so change code accordingly
      result = calc_sim(items[A], items[B])
      sim[A][B] = result # Copy result to both A,B and B,A as they are equal
      sim[B][A] = result

但实际上这两种算法都是O(n)n2

【讨论】:

  • 现在calc_sum 将获得索引,而不是实际的
  • 是的,我记下了它,但是@abc 有一个更好的答案......stackoverflow.com/a/65544844/2180316
  • for B in range(A, ...不错的技巧,这将有效地切断镜像的一半。
  • 它不是很 Pythonic,你应该使用 itertools 方法。
猜你喜欢
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 2016-05-17
  • 2018-12-21
相关资源
最近更新 更多