Python随机生成由0和1组成的数组

4
我希望随机生成一个长度为n的由1和长度为m的由0组成的数组。
我想到了以下解决方案:
  1. 生成由1组成的数组(np.ones)
  2. 生成由0组成的数组(np.zeros)
  3. 将它们合并成一个数组(np.hstack)
  4. 打乱结果数组(np.random.shuffle)
似乎不是很自然的解决方案。有没有更具Python风格的解决方法?

你想要一个由恰好n个1和m个0组成的数组,还是一个由n+m个元素组成,平均而言有n个1和m个0的数组? - abarnert
恰好有n个1和m个0 - Tengis
1
顺便提一下,你可能想使用 np.random.shuffle 而不是 random.shuffle - abarnert
你的解决方案看起来非常好,而且很符合Python的风格,如果你想要精确的1和0的数量。 - Bas Swinckels
4个回答

9

您的解决方案看起来很合理。它准确地说明了它正在做什么,并且清晰明了。

让我们比较一下您的实现:

a = np.hstack((np.ones(n), np.zeros(m)))
np.random.shuffle(a)

...有一个明显的替代方案:

a = np.ones(n+m)
a[:m] = 0
np.random.shuffle(a)

这样做可以节省一些时间,因为不需要分配和移动大量数据块,但是需要更深入理解。

如果使用Python而不是NumPy来完成此操作:

a = np.array([1]*n + [0]*m)
np.random.shuffle(a)

... 更为简洁,但似乎不太符合NumPy的习惯用语(就像使用np.array([1]*n)不如使用np.ones(n)一样),而且它会变得更慢、使用更多内存,并且没有什么好处。(您可以通过使用np.fromiter来改进内存,但这显然不会更简洁。)

当然,��果您需要执行此操作不止一次,最好是将其拆分为函数。这样函数的名称将解释其作用,并且任何不太复杂的解决方案都将非常容易理解...


1

我会创建一个由n个1和m个0组成的数组,如下:

a = np.array([1] * n + [0] * m)

然后我会在它上面调用np.random.shuffle()

你为什么要这样做?它会变得更慢,使用更多的内存,而且很难看到补偿性的好处。 - abarnert
1
这对我来说最容易理解(因此,我认为同事们也是如此)。在内存或速度成为问题并且代码的这一部分成为瓶颈之前,这是唯一重要的事情。 - RemcoGerlich
我不知道np.random.shuffle,我会编辑以使用它。 - RemcoGerlich
“np.hstack(np.ones(n), np.zeros(m))”有什么难以理解的?这直接用NumPy术语说明了它的作用。你会说“np.array([1] * n)”比“np.ones(n)”更易读吗? - abarnert
仅为了稍后将其转换为数组而创建列表对于大型数据来说速度较慢,最好使用np.onesnp.zeros,并将它们与concatenate一起使用,正如OP在他的问题中建议的那样。 - Bas Swinckels

0
使用 `numpy.random.permutation`:
a = numpy.random.permutation([1] * n + [0] * m)

或者,使用数组代替初始列表:

a = numpy.random.permutation(numpy.concatenate(np.ones(n), np.zeros(m)))

关于numpy中的concatenatehstack之间的区别,我了解不够,它们在这里似乎产生相同的结果。


为什么要使用“排列”来制作一个洗牌副本,而不是在原地进行洗牌?我可以看到将整个过程变成表达式的好处,在纯Python代码中,我可能会写出类似这样的代码,但在NumPy代码中,它似乎不太符合惯用法。 - abarnert
原地洗牌可能确实更好。我只是注意到permutation似乎是numpy中纯Python sorted(或者更确切地说是random.shuffle的假想对应物random.shuffled)的“等价物”。 - chepner
是的,有点奇怪的是 np.random 有一个 shuffled 的等效函数,但你通常不需要它,而标准库的 random 却没有这样一个函数,而你通常会需要它... - abarnert
关于 concatenatehstack 的区别:如果你没有传递 axis 参数并且你有 1D 数组,那么它们之间根本没有区别;这只是一个问题,对于给定的问题,哪个更易读。我觉得我会选择 concatenate,但既然原帖中选择了 hstack,我想最好还是坚持使用它。 - abarnert

0

我认为你的解决方案很合适,因为它易读且符合 Python 风格。但你没有说明内存或性能是否需要考虑。np.random.shuffle 可能已经达到了 O(m + n) 的效率,但其他答案表明它可能会进行多次遍历来打乱值。你可以使用以下代码在单次遍历中实现 O(m + n) 的效率且无需额外的内存开销:

import random
m = 600 # zeros
n = 400 # ones

result = []
while m + n > 0:
    if (m > 0 and random.random() < float(m)/float(m + n)):
        result.append(0)
        m -= 1
    else:
        result.append(1)
        n -= 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接