【问题标题】:Faster/lazier way to evenly and randomly split m*n into n group (each has m elements) in python更快/更懒惰的方式在 python 中将 m*n 均匀随机分成 n 组(每个组有 m 个元素)
【发布时间】:2021-07-10 08:33:22
【问题描述】:

我想将m*n 元素(例如,1、2、...、m*n)随机均匀地分成n 组,这样每个组都有m 随机元素。每个组将同时处理来自其自己组的k (k>=1) 元素,并且以相同的速度(通过某种同步机制),直到所有组都处理完自己的所有元素。实际上每个组都在一个独立的进程/线程中。

我使用numpy.random.choice(m*n, m*n, replace=False)先生成排列,然后索引每个组的排列结果。

问题是当m*n非常大时(例如>=1e8),速度很慢(几十秒或几分钟)。

有没有更快/更懒惰的方法来做到这一点?我想也许这可以用更懒的方式来完成,不是第一次生成置换结果,而是先生成一个生成器,在每组中,每次生成k个元素,其效果应该和我目前使用的方法。但是我不知道如何实现这种懒惰的方式。而且我不确定这是否可以实际实施。

【问题讨论】:

  • 您的目标似乎是由多个线程并行生成 N 项的排列。以下内容可能会为您指明正确的方向:github.com/lorenzhs/sampling。此外,生成一个排列相当于生成 N 个指数变量并对它们进行排序 (arxiv.org/pdf/1903.00227.pdf)。如果这有助于您找到答案,您可以发布它。
  • @PeterO。谢谢!看起来很有希望!我先试试看。
  • 您找到解决方案了吗?如果是这样,您应该将该解决方案作为答案发布。
  • @PeterO。我还没有找到令人满意的解决方案,但我组成并实现了一个序列服务器,每次使用 Fisher-yates 算法生成一个数字,并将生成的数字放入 n 队列以供 n 进程从中获取。

标签: python random generator permutation lazy-sequences


【解决方案1】:

您可以创建一个生成器,该生成器将逐步打乱(复制)列表并懒惰地产生不同的组:

import random
def rndGroups(A,size):
    A = A.copy()                    # work on a copy (if needed)
    p = len(A)                      # target position of random item
    for _ in range(0,len(A),size):  # work in chunks of group size
        for _ in range(size):       # Create one group 
            i = random.randrange(p) # random index in remaining items
            p -= 1                  # update randomized position
            A[i],A[p] = A[p],A[i]   # swap items
        yield A[p:p+size]           # return shuffled sub-range

输出:

A  = list(range(100))
iG = iter(rndGroups(A,10)) # 10 groups of 10 items
s  = set()                 # set to validate uniqueness
for _ in range(10):  # 10 groups
    g = next(iG)     # get the next group from generator
    s.update(g)      # to check that all items are distinct
    print(g)
print(len(s))        # must get 100 distinct values from groups

[87, 19, 85, 90, 35, 55, 86, 58, 96, 68]
[38, 92, 93, 78, 39, 62, 43, 20, 66, 44]
[34, 75, 72, 50, 42, 52, 60, 81, 80, 41]
[13, 14, 83, 28, 53, 5, 94, 67, 79, 95]
[9, 33, 0, 76, 4, 23, 2, 3, 32, 65]
[61, 24, 31, 77, 36, 40, 47, 49, 7, 97]
[63, 15, 29, 25, 11, 82, 71, 89, 91, 30]
[12, 22, 99, 37, 73, 69, 45, 1, 88, 51]
[74, 70, 98, 26, 59, 6, 64, 46, 27, 21]
[48, 17, 18, 8, 54, 10, 57, 84, 16, 56]
100

这将花费与预洗列表一样长的时间(如果不是更长的话),但它可以让您随时启动/提供线程,从而增强并行度

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    • 2020-08-14
    • 2013-02-24
    相关资源
    最近更新 更多