具有特定比例的二进制随机数组?

92

如何有效(可能使用Matlab术语进行向量化)地按特定比例生成随机数量的0和1?特别是使用Numpy?

由于我的情况对于1/3很特殊,我的代码是:

import numpy as np 
a=np.mod(np.multiply(np.random.randomintegers(0,2,size)),3)

但是是否有任何内置函数可以更有效地处理这种情况,至少对于 K/N 的情况,其中K和N是自然数?


2
你需要比例恰好是给定的值,还是那只是样本的预期比例? - Warren Weckesser
此外,当“size”不可被3整除时,对于1/3的情况应该怎么处理?抛出异常?四舍五入/向下取整/截断?加权随机舍入(因此10有2/3的概率为3和1/3的概率为4)? - abarnert
@WarrenWeckesser,这在我的情况下是预期的比例。我希望您没有删除您的答案,这样我就可以接受它。 - Cupitor
1
@Naji:我恢复了我的答案。如果你需要精确的比例,那种方法是行不通的。 - Warren Weckesser
1
@Naji:你想要什么?我希望它能创造一万亿美元,但它只给了我一个数组。我想我还不够相信它。 ;) - abarnert
显示剩余7条评论
7个回答

131

另一种方法是使用 np.random.choice

>>> np.random.choice([0, 1], size=(10,), p=[1./3, 2./3])
array([0, 1, 1, 1, 1, 0, 0, 0, 0, 0])

14
请注意,这种方法将不能给您所要求的零和一的确切比例。 @mdml下面的答案会给出确切比例。 - abcd
true,而且既然被接受了,我认为Cupitor可能在他的程序中添加了一个bug。 - JFFIGK
1
@JFFIGK,dbliss:这个问题在评论中已经讨论过了。那些评论还在,你可以去看一下。 - Warren Weckesser
由于提到的链接已经失效,请查看:numpy.random.choice - Alireza Rezaee

51

一个简单的方法是首先生成一个带有所需零和一比例的 ndarray

>>> import numpy as np
>>> N = 100
>>> K = 30 # K zeros, N-K ones
>>> arr = np.array([0] * K + [1] * (N-K))
>>> arr
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1])

然后你只需对数组进行shuffle操作,使其分布随机:

>>> np.random.shuffle(arr)
>>> arr
array([1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0,
       1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1,
       1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
       0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
       1, 1, 1, 0, 1, 1, 1, 1])

请注意,与二项式方法相比,此方法将为您提供所请求的零/一的精确比例。如果您不需要精确比例,则二项式方法也可以正常工作。


我真是太蠢了!我忘记了二进制分发。实际上,在你之前有人发布了二进制文件,但他删除了他的答案(不知道为什么!!) - Cupitor
1
这非常聪明。 - mxmlnkn

23

如果我正确理解你的问题,你可以通过numpy.random.shuffle获得一些帮助。

>>> def rand_bin_array(K, N):
    arr = np.zeros(N)
    arr[:K]  = 1
    np.random.shuffle(arr)
    return arr

>>> rand_bin_array(5,15)
array([ 0.,  1.,  0.,  1.,  1.,  1.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,
        0.,  0.])

20
你可以使用numpy.random.binomial。例如,假设frac是1的比例:
In [50]: frac = 0.15

In [51]: sample = np.random.binomial(1, frac, size=10000)

In [52]: sample.sum()
Out[52]: 1567

2
这并不像mdml的答案那样保证正确的比例。 - Epimetheus
@John,这个在问题评论区已经讨论过了。你可以去看一下。 - Warren Weckesser
我现在明白了!当然,那个问题需要编辑,因为它要求特定的比例。 - Epimetheus

1
简单来说:我认为在这个问题中,使用整数列表和概率分布是不直观且过度的解决方法。你可以先使用 bool,然后根据需要转换为 int(尽管保留为 bool 数组在大多数情况下也可行)。
>>> import numpy as np
>>> np.random.random(9) < 1/3.
array([False,  True,  True,  True,  True, False, False, False, False])   
>>> (np.random.random(9) < 1/3.).astype(int)
array([0, 0, 0, 0, 0, 1, 0, 0, 1])    

这并不保证像mdml的答案那样正确地比例。 - Epimetheus
OP 表示他们希望 1/3 成为预期的 1 的比例,而不是精确的比例。 - Galactic Ketchup

1
另一种获取1和0的确切数量的方法是使用np.random.choice进行无重复索引采样:
arr_len = 30
num_ones = 8

arr = np.zeros(arr_len, dtype=int)
idx = np.random.choice(range(arr_len), num_ones, replace=False)
arr[idx] = 1

输出:
arr

array([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
       0, 0, 0, 0, 0, 1, 0, 0])

0
你可以通过以下方法在一行中直接生成具有随机二进制成员(0和1)的nd-array。你也可以使用np.random.random()代替np.random.uniform()
>>import numpy as np
>>np.array([[round(np.random.uniform()) for i in range(3)] for j in  range(3)])
array([[1, 0, 0],
       [1, 1, 1],
       [0, 1, 0]])
>>

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