Binary random array with a specific proportion of ones?

67,557

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])
Share:
67,557

Related videos on Youtube

Cupitor
Author by

Cupitor

Updated on August 04, 2020

Comments

  • Cupitor
    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
      Warren Weckesser over 10 years
      Do you need the proportion to be exactly the given value, or is that just the expected proportion of the sample?
    • abarnert
      abarnert over 10 years
      Also, 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
      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
      Cupitor over 10 years
      @abarnert, that was the expected case!
    • Warren Weckesser
      Warren Weckesser over 10 years
      @Naji: I restored my answer. If you had needed the exact proportion, that method wouldn't work.
    • Cupitor
      Cupitor over 10 years
      @WarrenWeckesser, and I accepted it! Well even my method was not exact as I make a random sequence first!
    • abarnert
      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
      Cupitor over 10 years
      @abarnert, a binomial sample with N=2 and p=ration will generate whatever I want I believe!
    • Warren Weckesser
      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 use p=[1-frac, frac].
    • abarnert
      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
      Cupitor over 10 years
      @abarnert, ha ha ha! good one! well you know what I mean :)
    • Cupitor
      Cupitor over 10 years
      @WarrenWeckesser, then the Oscar goes to Jaime! :D
  • Cupitor
    Cupitor over 10 years
    How 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
    abcd almost 6 years
    note that this approach will not give you the exact proportion of zeros and ones you request . . . the answer by @mdml below will.
  • mxmlnkn
    mxmlnkn almost 5 years
    This is quite clever
  • JFFIGK
    JFFIGK over 4 years
    true, and since it is accepted, I think Cupitor might have added a bug to his program
  • Epimetheus
    Epimetheus over 4 years
    This doesn't guarantee the correct proportion of ones like mdml's answer does.
  • Epimetheus
    Epimetheus over 4 years
    This doesn't guarantee the correct proportion of ones like mdml's answer does.
  • Warren Weckesser
    Warren Weckesser over 4 years
    @John, this was discussed in the comments to the question. Take a look.
  • Warren Weckesser
    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
    Galactic Ketchup over 4 years
    The OP said they wanted 1/3 to be the expected proportion of 1s, not the exact proportion.
  • Epimetheus
    Epimetheus over 4 years
    I see now! Of course the question needs editing then as it asks for specific proportion.
  • Alireza Rezaee
    Alireza Rezaee about 2 years
    Since the mentioned link is broken, see: numpy.random.choice.