Binary random array with a specific proportion of ones?
Solution 1
If I understand your problem correctly, you might get some help with 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.])
Solution 2
Yet another approach, using 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])
Solution 3
A simple way to do this would be to first generate an ndarray
with the proportion of zeros and ones you want:
>>> 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])
Then you can just shuffle
the array, making the distribution random:
>>> 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])
Note that this approach will give you the exact proportion of zeros/ones you request, unlike say the binomial approach. If you don't need the exact proportion, then the binomial approach will work just fine.
Solution 4
You can use numpy.random.binomial
. E.g. suppose frac
is the proportion of ones:
In [50]: frac = 0.15
In [51]: sample = np.random.binomial(1, frac, size=10000)
In [52]: sample.sum()
Out[52]: 1567
Solution 5
Another way of getting the exact number of ones and zeroes is to sample indices without replacement using 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
Out:
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])
Related videos on Youtube
Cupitor
Updated on August 04, 2020Comments
-
Cupitor almost 4 years
What is the efficient(probably vectorized with Matlab terminology) way to generate random number of zeros and ones with a specific proportion? Specially with Numpy?
As my case is special for
1/3
, my code is:import numpy as np a=np.mod(np.multiply(np.random.randomintegers(0,2,size)),3)
But is there any built-in function that could handle this more effeciently at least for the situation of
K/N
where K and N are natural numbers?-
Warren Weckesser over 10 yearsDo you need the proportion to be exactly the given value, or is that just the expected proportion of the sample?
-
abarnert over 10 yearsAlso, what should happen for the 1/3 case when
size
is not divisible by 3? Exception? Round/floor/trunc? Weighted random round (so 10 has a 2/3 chance of 3 and a 1/3 chance of 4)? -
Cupitor over 10 years@WarrenWeckesser, its the expected proportion in my case. I wished you didn't deleter your answer so I would have accepted it.
-
Cupitor over 10 years@abarnert, that was the expected case!
-
Warren Weckesser over 10 years@Naji: I restored my answer. If you had needed the exact proportion, that method wouldn't work.
-
Cupitor over 10 years@WarrenWeckesser, and I accepted it! Well even my method was not exact as I make a random sequence first!
-
abarnert over 10 years@Naji: A binomial or other random distribution functon won't give you a 2/3 chance of 3 and a 1/3 chance of 4; it'll give you a high chance of 3, a lower chance of 4, an even lower chance of 2, an even lower chance of 5, etc. Is that what you wanted?
-
Cupitor over 10 years@abarnert, a binomial sample with N=2 and p=ration will generate whatever I want I believe!
-
Warren Weckesser over 10 years@Naji: Thanks, but I think I like @Jaime's answer more than mine. It seems even more explicit. For an arbitrary proportion
frac
, just usep=[1-frac, frac]
. -
abarnert over 10 years@Naji: Whatever you want? I wanted it to generate a trillion dollars, and all it gave me was an array. I suppose I'm not believing hard enough. ;)
-
Cupitor over 10 years@abarnert, ha ha ha! good one! well you know what I mean :)
-
Cupitor over 10 years@WarrenWeckesser, then the Oscar goes to Jaime! :D
-
-
Cupitor over 10 yearsHow stupid of me! Right I forgot about binary distribution. Actually somebody posted binary right before you but he deleted his answer(dont know why!!)
-
abcd almost 6 yearsnote that this approach will not give you the exact proportion of zeros and ones you request . . . the answer by @mdml below will.
-
mxmlnkn almost 5 yearsThis is quite clever
-
JFFIGK over 4 yearstrue, and since it is accepted, I think Cupitor might have added a bug to his program
-
Epimetheus over 4 yearsThis doesn't guarantee the correct proportion of ones like mdml's answer does.
-
Epimetheus over 4 yearsThis doesn't guarantee the correct proportion of ones like mdml's answer does.
-
Warren Weckesser over 4 years@John, this was discussed in the comments to the question. Take a look.
-
Warren Weckesser over 4 years@JFFIGK, dbliss: this was discussed in the comments to the question. Those comments are still there, so take a look.
-
Galactic Ketchup over 4 yearsThe OP said they wanted 1/3 to be the expected proportion of 1s, not the exact proportion.
-
Epimetheus over 4 yearsI see now! Of course the question needs editing then as it asks for specific proportion.
-
Alireza Rezaee about 2 yearsSince the mentioned link is broken, see: numpy.random.choice.