【问题标题】:Parallel nested for loop in PythonPython中的并行嵌套for循环
【发布时间】:2021-05-07 19:52:41
【问题描述】:

我正在尝试使用在线资源来并行化我的嵌套 for 循环,但似乎无法理解它是如何正常工作的。

这是我的原始函数(它计算存储在列表中的两个字符串的每个组合之间的余弦相似度)

def compute_similarity(list):

  for i in range(len(list)):
      for j in range(len(list)):
    
        if i == j:
          pass
    
        else: 
          similarity = get_sim(list[i], list[j])
          sim_df.iloc[i,j] = similarity

我尝试使用多处理库,但没有任何运气。任何帮助表示赞赏。谢谢!

【问题讨论】:

  • 顺便说一句,im_df.iloc[i,j] = similarity 非常慢。使用im_df.iat[i, j] = similarity
  • list大概多长时间?
  • 您可以通过使用for j in range(i+1, len(list)) 并在每次迭代中同时设置[i,j][j,i]get_sim 的调用次数减半
  • 没有任何运气是什么意思。 ' 意思是?具体一点:一个错误,没有改进,什么?
  • 这不是 minimal, reproducible example 使用真实数据,有人可以实际测试解决方案以查看多处理解决方案是否能提高性能。您需要更新您的问题。

标签: python pandas multiprocessing trigonometry


【解决方案1】:

(可能跑题了)

l = [38, 12, 44, 24, 43, 3, 19, 31, 47, 31]
m = np.ones((len(l), len(l))) * l
>>> m
array([[38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.],
       [38., 12., 44., 24., 43.,  3., 19., 31., 47., 31.]])

申请cosine similarity:

num = m.T.dot(m)
norm = (m ** 2).sum(axis=0) ** 0.5
>>> num / (norm * norm.T)
array([[ 1.        ,  3.16666667,  0.86363636,  1.58333333,  0.88372093,
        12.66666667,  2.        ,  1.22580645,  0.80851064,  1.22580645],
       [ 0.31578947,  1.        ,  0.27272727,  0.5       ,  0.27906977,
         4.        ,  0.63157895,  0.38709677,  0.25531915,  0.38709677],
       [ 1.15789474,  3.66666667,  1.        ,  1.83333333,  1.02325581,
        14.66666667,  2.31578947,  1.41935484,  0.93617021,  1.41935484],
       [ 0.63157895,  2.        ,  0.54545455,  1.        ,  0.55813953,
         8.        ,  1.26315789,  0.77419355,  0.5106383 ,  0.77419355],
       [ 1.13157895,  3.58333333,  0.97727273,  1.79166667,  1.        ,
        14.33333333,  2.26315789,  1.38709677,  0.91489362,  1.38709677],
       [ 0.07894737,  0.25      ,  0.06818182,  0.125     ,  0.06976744,
         1.        ,  0.15789474,  0.09677419,  0.06382979,  0.09677419],
       [ 0.5       ,  1.58333333,  0.43181818,  0.79166667,  0.44186047,
         6.33333333,  1.        ,  0.61290323,  0.40425532,  0.61290323],
       [ 0.81578947,  2.58333333,  0.70454545,  1.29166667,  0.72093023,
        10.33333333,  1.63157895,  1.        ,  0.65957447,  1.        ],
       [ 1.23684211,  3.91666667,  1.06818182,  1.95833333,  1.09302326,
        15.66666667,  2.47368421,  1.51612903,  1.        ,  1.51612903],
       [ 0.81578947,  2.58333333,  0.70454545,  1.29166667,  0.72093023,
        10.33333333,  1.63157895,  1.        ,  0.65957447,  1.        ]])

>>> pd.DataFrame(num / (norm * norm.T), index=l, columns=l).round(2)
      38    12    44    24    43     3     19    31    47    31
38  1.00  3.17  0.86  1.58  0.88  12.67  2.00  1.23  0.81  1.23
12  0.32  1.00  0.27  0.50  0.28   4.00  0.63  0.39  0.26  0.39
44  1.16  3.67  1.00  1.83  1.02  14.67  2.32  1.42  0.94  1.42
24  0.63  2.00  0.55  1.00  0.56   8.00  1.26  0.77  0.51  0.77
43  1.13  3.58  0.98  1.79  1.00  14.33  2.26  1.39  0.91  1.39
3   0.08  0.25  0.07  0.12  0.07   1.00  0.16  0.10  0.06  0.10
19  0.50  1.58  0.43  0.79  0.44   6.33  1.00  0.61  0.40  0.61
31  0.82  2.58  0.70  1.29  0.72  10.33  1.63  1.00  0.66  1.00
47  1.24  3.92  1.07  1.96  1.09  15.67  2.47  1.52  1.00  1.52
31  0.82  2.58  0.70  1.29  0.72  10.33  1.63  1.00  0.66  1.00

【讨论】:

  • 我想我跑题了,对此我很抱歉,但这段代码可能应该比嵌套循环运行得更快。因此,也许您不必使用多处理。
  • 感谢您的回复。我正在尝试跟随,但我对 denom/norm/norm.T 部分感到有些困惑。我不完全理解它是如何缩放以计算每个组合的。
  • Numpy 使用向量化函数并将其执行委托给高度优化的并行 C/Fortran 函数。 Python 中的循环可能很慢,并且多处理会增加开销,NumPy 矢量化函数可能是最好的折衷方案。
【解决方案2】:

在 python 中,进行基本的并行处理相对容易。您可以将函数放入继承自 Thread 的类中,然后为每个计算部分旋转新线程。

class SentenceThread(Thread):
    def __init__(
        self,
        sentence: string,
    ):
        super().__init__()
        self.sentence = sentence


    def run(self) -> None:
        #do your thing with cosine calculation
        pass


sentence_threads = []

for sentence in sentences:
    sentence_thread = SentenceThread(sentence)
    sentence_thread.start()
    sentence_threads.append(sentence_thread)

for sentence_thread in sentence_threads:
    sentence_thread.join()

当您在实例上调用start 时,run 函数将在新线程中调用。所以你需要把你的计算繁重的函数放在那里。

如需进一步参考,请查看here

【讨论】:

  • 当然,在 CPython 中,这实际上不会并行运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
相关资源
最近更新 更多