【问题标题】:Pythonic Nested for - loops in PythonPythonic 嵌套 for - Python 中的循环
【发布时间】:2020-06-08 05:47:38
【问题描述】:

我正在处理嵌套 for 循环的代码。 a_listb_list 是元组列表,其中每个元组由两个张量 [(tens1, tens2), ...] 组成。我正在尝试计算a_list 中的每个tens1b_list 中的每个tens1 的相似性。下面是我的代码。嵌套循环似乎是一个瓶颈。有没有更好的方法(pythonic)我可以重写循环?

a2b= defaultdict(dict)
b2a= defaultdict(dict)
ab_sim = []

for a, vec_a in a_list:
    for b, vec_b in b_list:
        # Ignore combination if the first element in both a and b are same
        if a[0] == b[0]:
            continue
        # Calculate cosine similarity of combination
        sim = self.calculate_similarity(vec_a, vec_b )
        a2b[a][b] = sim
        b2a[b][a] = sim
        ab_sim.append(sim)

calculate_similarity 只是一种计算余弦相似度的方法。 a_listb_list 可以是任意大小。我有 b2aa2b 因为我需要它们来进行其他计算。

【问题讨论】:

  • 如果你真的需要所有余弦相似度的完整 n×m 矩阵,我认为没有办法计算所有这些。如果你可以编辑你的问题来解释为什么你需要所有这些余弦相似性,也许我们可以避免XY problem
  • 你意识到你实际上是在比较第二个张量吗?第一个存储到a,第二个存储到vec_abvec_b 相同。你正在比较vec_avec_b。如果您希望ab 成为索引,则需要使用enumerate
  • 作为一个小的优化,你不一定需要a2bb2a,如果你用排序的元组键将它们存储在一个dict中。
  • @Adirio 我们不知道a_list/b_list 的形状,它们可能已经是索引了。
  • 所以我试图计算两种语言之间句子表示的余弦相似度。我有a_listb_list 是一个元组列表,其中每个元组都包含(句子,embedding_representation)。

标签: python python-3.x oop for-loop pytorch


【解决方案1】:

您可以使用字典理解:

a2b = {a: {b: self.calculate_similarity(vec_a, vec_b )
       for (b, vec_b) in b_list if a[0] != b[0]} for (a, vec_a) in a_list}

【讨论】:

  • 这仍然使用两个嵌套循环,但我认为我们无法进一步优化。
  • @JesujobaALABI 确实之前的 dict 理解是错误的,你现在可以检查一下吗?这次应该是正确的
【解决方案2】:

你也可以使用product from itertools:

from itertools import product
result = {(a,b): self.calculate_similarity(vec_a, vec_b) 
          if a[0] != b[0] else 1 
          for ((a, vec_a) ,(b, vec_b)) in product(a_list, b_list)}

请注意,您会得到一个带有元组索引的字典,而不是两个冗余字典。

已编辑:要恢复这两个字典,您可以使用字典理解:

a2b = {a: {_b:v for (_a,_b), v in result.items() if _a==a} for (a,b) in result.keys()}
b2a = {b: {_a:v for (_a,_b), v in result.items() if _b==b} for (a,b) in result.keys()}

要获取相似度值列表,可以使用ab_sim = list(result.values())

【讨论】:

  • 好@Itamar!我的字典不是多余的。我将它们用于我决定不包括在此处的其他计算
  • 它们是多余的,因为它们拥有相同的信息。您可以使用其他数据结构 - 例如,我建议您探索具有多索引的 pandas 数据帧/系列:pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html
  • 尽管如此,我编辑了我的问题,以展示如何从联合字典中获取两个字典,如果您更喜欢这种结构。
  • 我需要将sim(相似度)放入ab_sim.append(sim) 等列表中。我需要一个单独的循环吗?
  • 不是真的,那个列表只是ab_sim = list(result.values())
【解决方案3】:

我认为存储这些信息最自然的方式是在矩阵中

from random import random
import numpy as np
n=3
a=[ (n*np.random.rand(n)//1, n*np.random.rand(n)//1) for _ in range(3) ]
b=[ (n*np.random.rand(n)//1, n*np.random.rand(n)//1) for _ in range(3) ]


similarity = lambda x,y: np.dot(x, y)/(np.linalg.norm(x)*np.linalg.norm(y))

sim_matrix = [[ similarity(x,y) if x[0]!=y[0] else np.inf for y,_ in b  ] for x,_ in a]

print(*sim_matrix, sep="\n")

完整的代码。

【讨论】:

  • 但是我添加了重要的代码,因为其他代码只是用于模拟他已经在他们的问题中拥有的数据,我仍然会更新它
  • 谢谢;我没有直接删除答案,因为您的答案中显然有重要的一行。很遗憾,您提供了更广泛的背景作为图像。产生的输出也只是文本,顺便说一下,输出的图像并没有添加任何有用的信息。
猜你喜欢
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
相关资源
最近更新 更多