【问题标题】:Which is the more efficient way to choose a random pair of objects from a list of lists or tuples?从列表或元组列表中选择一对随机对象的更有效方法是什么?
【发布时间】:2017-04-13 08:53:23
【问题描述】:

我有一个具有这种结构的二维坐标列表:

coo = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]

coo[0] 是存储在元组中的第一个坐标。

我想选择两个不同的随机坐标。我当然可以使用这种方法:

import numpy  as np
rndcoo1 = coo[np.random.randint(0,len(coo))]
rndcoo2 = coo[np.random.randint(0,len(coo))]
if rndcoo1 != rndcoo2:
     #do something

但是因为我必须重复这个操作 1'000'000 次,所以我想知道是否有更快的方法来做到这一点。 np.random.choice() 不能用于 2d 数组有没有我可以使用的替代方法?

【问题讨论】:

  • coo 实际上是一个 numpy 数组吗?您是否尝试过random.choice 而不是np.random.choicerndcoo1rndcoo2 应该不同吗?
  • @ G M rndcoo1,rndcoo2 = [coo[np.random.choice(len(coo))] for __ in range(2)]
  • @tobias_k coo 如果需要可以是一个列表。实际上我不知道可以使用 random.choice 并且看起来更好。我必须选择两个不同的坐标不能相同。
  • @GM random.sample(coo, 2) Python 不会让你变得更快。
  • @tobias_k 我发现random.choicenp.random.randint 稍慢

标签: python performance numpy random


【解决方案1】:

在这篇文章中列出的是一种矢量化方法,它可以让我们一次性为多次迭代提供大量这样的随机选择,而无需循环遍历这些多次迭代。这个想法使用np.argpartition 并受到this post 的启发。

这是实现 -

def get_items(coo, num_items = 2, num_iter = 10):
    idx = np.random.rand(num_iter,len(coo)).argpartition(num_items,axis=1)[:,:2]
    return np.asarray(coo)[idx]

请注意,我们将返回一个3D 数组,其中第一个维度是迭代次数,第二个维度是每次迭代要做出的选择数,最后一个维度是每个元组的长度。

样本运行应该会呈现更清晰的画面 -

In [55]: coo = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]

In [56]: get_items(coo, 2, 5)
Out[56]: 
array([[[2, 0],
        [1, 1]],

       [[0, 0],
        [1, 1]],

       [[0, 2],
        [2, 0]],

       [[1, 1],
        [1, 0]],

       [[0, 2],
        [1, 1]]])

运行时测试比较循环实现与random.sample 中列出的@freakish's post -

In [52]: coo = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0)]

In [53]: %timeit [random.sample(coo, 2) for i in range(10000)]
10 loops, best of 3: 34.4 ms per loop

In [54]: %timeit get_items(coo, 2, 10000)
100 loops, best of 3: 2.81 ms per loop

【讨论】:

    【解决方案2】:

    coo 只是一个例子,还是你的坐标实际上是等距的?如果是这样,您可以像这样对M 2D 坐标进行采样:

    import numpy
    
    N = 100
    M = 1000000
    coo = numpy.random.randint(0, N, size=(M, 2))
    

    当然,您也可以使用加法和乘法来偏置和缩放分布,以解决不同的步长和偏移量。

    如果您在使用较大的Ms 时遇到内存限制,您当然可以对较小的尺寸进行采样,或者使用size=2 仅对一个包含 2 个值的数组进行采样。

    【讨论】:

      【解决方案3】:
      import random
      result = random.sample(coo, 2)
      

      会给你预期的输出。它(可能)与 Python 一样快。

      【讨论】:

        猜你喜欢
        • 2012-11-01
        • 1970-01-01
        • 2014-03-10
        • 2023-01-11
        • 2017-04-26
        • 1970-01-01
        • 1970-01-01
        • 2010-09-08
        • 1970-01-01
        相关资源
        最近更新 更多