0

I have a 3D array of size NxNxN. I would like to fill this array with random booleans, which I can do with:

a = np.random.choice([False,True],size=(N,N,N))

However, I would like the likelihood (or p-value) of choosing either True or False to be based on the element's position in the array. I thought maybe I could do this with the p-value parameter, but that only then works for selecting how often True/False is chosen for the entire array.

Is there any way to set specific p-values for the entire (N,N,N) array? I guess that would amount to an (N,N,N,2) array then, with the extra 2 being for the p-value for False and p-value for True (though p_True = 1 - p_False). I feel like there's a simpler way to do this that I'm not thinking of.

Edit: So say I want to create a simple array, a, of shape (1,2) (just two elements, but multidimensional on purpose). I want to fill these two elements with True/False. I have another array filled with the likelihood or p-value with which I want those elements to be False, say p_False, where p_False.shape = (1,2). Let's say I want the first element to have a 25% chance of being False, but the second element to have a 50% chance of being false, so then p_False = np.array([0.25,0.5]).

I tried something along the lines of:

a = np.random.choice([[False,True],[False,True]],p=[[.25,.75],[.5,.5]])

but I got a ValueError: a must be 1-dimensional.

tomerg
  • 353
  • 2
  • 12
  • Can you elaborate on `to be based on the element's position in the array`? Maybe use a small 2D `(N,N)` array to demonstrate? – Divakar Jun 18 '20 at 14:36

2 Answers2

1

To generate an array with different probabilities, you can use the following code:

# define an initial value of N
N = 512

# generate an array of probabilities. You can eventually build your own, since the size is respected
prob_array = np.array((range(0,N*N*N)))

# rescale the probabilities between 0 and 1
prob_array = (prob_array - np.min(prob_array)) / (np.max(prob_array) - np.min(prob_array))

# generate the random based on the probabilities, cast to booleans and reshape
np.reshape(np.array(np.random.binomial(1, p=prob_array, size=N*N*N), dtype=bool), (N,N,N))

This generates an array with lots of Falses in the beginning and lots of Trues in the end:

array([[[False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
        ...,
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False]],

       ...,


       [[ True,  True,  True, ...,  True,  True,  True],
        [ True,  True,  True, ...,  True,  True,  True],
        [ True,  True,  True, ...,  True,  True,  True],
        ...,
        [ True,  True,  True, ...,  True,  True,  True],
        [ True,  True,  True, ...,  True,  True,  True],
        [ True,  True,  True, ...,  True,  True,  True]]])
Daniel Labbe
  • 1,979
  • 3
  • 15
  • 20
  • so this looks like its looping in python over each element of the array, correct? My actual NxNxN array could be of size 512x512x512, so may be slow. I tried with N=64 and kept getting the error: ValueError: probabilities are not non-negative. This error appears for N>5. Also, with N=5 I always get the same answer, the first four rows are all True, the 5th row is all False. – tomerg Jun 18 '20 at 14:54
  • Yes, it is potentially slow for a big N. The error was generated because N*N*N is bigger than 100, so 1 - elements greater than 100 will generate a negative probability, what is impossible. – Daniel Labbe Jun 18 '20 at 14:57
  • Updated to clip the probabilities and generate the data without loops. – Daniel Labbe Jun 18 '20 at 15:23
0

Use the binomial method with an array of numbers in [0, 1]. Here is an example, which sets each element to 0 or 1 depending on a randomly chosen probability:

import numpy
gen=numpy.random.Generator(numpy.random.PCG64())
ret=gen.binomial(1, gen.uniform(size=(3, 3, 3)))

If you want each item to be True or False rather than 0 or 1, I'm afraid I don't know how to do so.

Note that numpy.random.Generator was introduced in NumPy 1.7. You are recommended to use the latest version of NumPy; in the meantime, you can use the following:

import numpy
ret=numpy.random.binomial(1, numpy.random.uniform(size=(3, 3, 3)))
Peter O.
  • 32,158
  • 14
  • 82
  • 96
  • It looks like Generator might be new. I have Numpy 1.15.1 and it doesn't appear to have it. I distribute this code so I'd like something not requiring updating Numpy versions. Is there a replacement with say RandomState or something else? – tomerg Jun 18 '20 at 14:59
  • Yes; Generator was introduced in Numpy 1.7. You are recommended to use the latest version of Numpy; in the meantime, you can use `numpy.random.binomial`/`.uniform`. – Peter O. Jun 18 '20 at 16:56