【问题标题】:Generating binary sequences without repetition生成不重复的二进制序列
【发布时间】:2021-04-17 02:47:19
【问题描述】:

我正在尝试生成仅包含 01 的序列。我已经编写了以下代码,并且可以正常工作。

import numpy as np

batch = 1000
dim = 32

while 1:
    is_same = False
    seq = np.random.randint(0, 2, [batch, dim])
    for i in range(batch):
        for j in range(i + 1, batch):
            if np.array_equal(seq[i], seq[j]):
                is_same = True
    if is_same:
        continue
    else:
        break

我的batch 变量有数千个。上面的这个循环大约需要 30 秒才能完成。这是另一个 for 循环的数据生成部分,该循环运行了大约 500 次迭代,因此非常慢。有没有更快的方法来生成这个序列列表而不重复?谢谢。

所需的结果是batch_size 序列的集合,每个序列的长度为dim,仅包含0s 和1s,这样集合中没有两个序列是相同的。

【问题讨论】:

  • 这可能更适合Code Review
  • 请讨论想要的和不想要的结果。也许有一个根本不同的解决方案。
  • @Yunnosch 我已经添加了想要的结果。我希望从我所做的编辑中可以清楚地看到不想要的结果。如果没有,我会添加它。谢谢。
  • 这是非常低效的。几个例子——除非你有 1000 个独特的序列,否则你会生成新的 1000 个并再次开始检查。和检查 - 你总是检查完整的 1000 对,而不是在第一对相同的序列之后突破。还有更多的改进空间。
  • 您可能需要更多地描述可接受和不可接受的结果。因为对于您所描述的,在二进制表示中列出连续递增的数字并将它们打乱是一种解决方案。这只会让你得到“较低的”batch_size 数字。但也许你想填充,使最后一个尽可能接近batch_size -1。如果您不矛盾,我会回答。

标签: python python-3.x performance numpy random


【解决方案1】:

您可以使用 random 模块中的 sample 函数将不重复的随机位模式作为整数获取。将这些整数转换为位是 numpy 更好的工作(与字符串操作相反)

def sequenceBatch(batch,dim):
    bits  = np.array(random.sample(range(2**dim),batch),dtype=np.int)
    masks = 2**np.arange(dim)
    return (np.bitwise_and(bits[:,None],masks)>0).astype(np.int)

这比你的函数快 500 多倍(比 Buran 的 generate2() 函数快 5 倍)

【讨论】:

    【解决方案2】:

    range(0, 2**dim + 1) 中生成batch 的数量int 将这些数字转换为二进制,然后转换为0a 和1s 的序列。

    from random import sample
    
    def generate(batch, dim):
        my_sample = [f'{n:0>32b}' for n in sample(range(2**dim+1), batch)]
        return [[int(n) for n in item] for item in my_sample]
    
    def generate2(batch, dim):
        return [list(map(int, f'{n:0>32b}')) for n in sample(range(2**dim+1), batch)]
    

    第二个有点快

    from timeit import timeit
    print(timeit("generate(1000, 32)", setup="from __main__ import generate", number=100))
    print(timeit("generate2(1000, 32)", setup="from __main__ import generate2", number=100))
    

    输出

    1.4956848690007973
    1.1187048860001596
    

    【讨论】:

    • 感谢您的宝贵时间,但my_sample 中的元素长度会有所不同,对吧?您如何确保在前面添加零以使所有的长度都相同?
    • 我建议进行一些更改的编辑。通过这些更改,这得到了我正在寻找的东西。谢谢!
    • 我在编辑答案时无意中删除了导入。 tuplelist - 由你决定。
    【解决方案3】:

    加快大量检查长序列的简单方法是使用散列。 为每个序列计算一个哈希码,然后为所有具有给定哈希的序列保留一个桶(或链表)。

    当您生成一个新序列时,您只需检查其哈希码的哈希桶中的重复项。例如使用 16 位哈希码,重复检查将快 65536 倍。

    【讨论】:

    • 你能分享一个代码示例或者一个链接来说明如何做到这一点吗?
    【解决方案4】:

    对于所描述的期望结果,您可以使用数字 0...batch_size-1 的二进制表示(乘以 (2^dim)/batch_size)并将它们打乱。
    这种方法效率更高,因为不会丢弃临时生成的数字,而且没有嵌套循环的时间复杂度要好得多。

    为了获得一个随机分量(未为所需结果定义,但有点明显),您可以在 0...( (2^dim)/batch_size -1) 范围内为每个分量添加一个随机数。由于如上所述生成的原始序列的间距,这也不会导致相同。随机数永远不会进入下一个生成数字的范围内。

    例如

    dim 5,batch_size 8

    sequential binary random total shuffled index
    0 00000 10 00010 5
    4 00100 00 00100 2
    8 01000 11 01011 6
    12 01100 11 01111 0
    16 10000 01 10001 3
    20 10100 00 10100 7
    24 11000 10 11010 1
    28 11100 00 11100 4

    剩下的就是洗牌,打破这种“连续运行”。

    【讨论】:

    • 谢谢,但您的序列将始终连续运行。假设我从x 开始,那么(至少)将持续运行直到x+32。很抱歉我没有把它放在想要的结果中,但这是我想要实现的一些随机性。
    • 在我的回答中,我忘记了我在评论中的洗牌。很好发现。
    猜你喜欢
    • 2013-08-19
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 2015-09-04
    • 2016-03-25
    相关资源
    最近更新 更多