5

I am trying to get a get a sequence of randomly chosen numbers when the condition is True.

I have a NumPy array full of Boolean numbers:

In [1]: multiples
Out[1]: array([False, False, False,  True,  True, 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, False, False, False,
               False, False, False,  True,  True, False,  True,  True, False,
               False, False, False,  True,  True, 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, False,
               False, False, False, False,  True,  True,  True, False,  True,
                True, False, False, False,  True,  True, False], dtype=bool)

And I want to convert it into an array of values based on the condition:

If the value is True return a randomly chosen number from [-1, 0, 1], or return 0.

So in the case of the above example, I want to output to look like:

Out[2]: array([ 0,  0,  0,  0,  1,  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,  0,  0,  0,  0,  0, -1,  0,  0, -1,  0,  0,  0,  0, -1,  1,  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,  0,  0,  0,  0,  0,
                1, -1, -1,  0,  1,  0,  0,  0,  0,  0,  0,  0])

There is numpy.where() which almost gives me what I want:

In [3]: numpy.where(multiples, numpy.random.choice([-1, 0, 1], 1), 0)
Out[3]: array([ 0,  0,  0, -1, -1,  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,  0,
                0,  0,  0,  0,  0, -1, -1,  0, -1, -1,  0,  0,  0,  0, -1, -1,  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,  0,  0,  0,  0,  0,
               -1, -1, -1,  0, -1, -1,  0,  0,  0, -1, -1,  0])

But the problem is that it executes numpy.random.choice([-1, 0, 1], 1) only once, and keeps that result and uses it everywhere. I want it to run for each time the value in multiples is True.

3 Answers 3

3
out = np.random.randint(-1, 2, multiples.shape)
out[~multiples] = 0
Sign up to request clarification or add additional context in comments.

2 Comments

Or use np.where : np.where(multiples,np.random.randint(-1, 2, multiples.shape),0).
In the same way, I can just use np.where(multiples, np.random.choice([-1, 0, 1], multiples.shape, replace=True), 0). Dang why didn't I think of that in the first place!?! Thanks @jmhl and @Divakar.
2

You could use np.random.choice to generate random numbers in the list [-1,0,1] and put them in an output array corresponding to True places in the input array, like so -

newvals = [-1,0,1] # Values to be put at places of True in input array

out = np.zeros(multiples.size,dtype=int) # Setup output array

# Finally use np.random.choice to get random numbers from newvals as many
# as there are True elements in input array and put into the output array 
# indexed by the corresponding True places in the input array
out[multiples] = np.random.choice(newvals, multiples.sum(), replace=True)

Sample run -

In [44]: multiples
Out[44]: 
array([ True,  True, False,  True,  True, False,  True,  True, False,
        True, False,  True, False,  True,  True,  True,  True, False,
        True,  True], dtype=bool)

In [45]: newvals
Out[45]: [9, 10, 11]

In [46]: out
Out[46]: 
array([11, 10,  0,  9,  9,  0, 10, 11,  0, 10,  0, 11,  0,  9, 10, 11,  9,
        0, 10, 10])

6 Comments

Why bother with nonzero?
@user2357112 Because I needed to get the count of nonzeros with idx.size. I suppose I could use multiples.sum() there.
The solution that you had before with idx and nonzero was more intuitive to me. In any case, great answer, I was struggling to solve it.
@LuisMiguel Well, if you imagine multiples as a boolean array, multiples.sum() would indicate the number of nonzeros in input array, so yeah needs a bit of thinking there. Whichever works :)
Or np.count_nonzero, which nonzero uses to preallocate its output arrays.
|
-1

Did you try to make a for loop ?

for k in range(0,your x size):
    for j in range(0, your y size):
        if array[k][j] == True:
            array[k][j] = (which value you want)
        else:
            array[k][j] = (which value you want)

If you want to record that, define a new matris as A=np.zeros((xsize,ysize), 'uint8') then add A[k][j] = array[k][j] in second for loop.

for showing it print (A) will help you..

5 Comments

For loops are very inefficient. Thank you for your answer, but it is very simplistic and inefficient. Please read more on how you can avoid loops in Python in the first place.
But it works. In design solutions there is 2 laws. 1-KEEP IT SIMPLE AND STUPID 2-THERE IS MORE THAN ONE WAY TO DO IT. But thank you for your inefficient comment. @Kartik
I don't just want to make it work. Even if it works in theory, if it takes longer than a certain time, it is still considered as fail. I have billions of records to process, and deadlines to meet. If a model doesn't work, I need to try other models, document the whole procedure, and a ton of other things in between. To do all that I need all the time I have between project start and deadline. Processor speed can only save that much time, hence the reason for optimization. People who I report to, will never agree to wait on for loops to finish.
The difference is between real world and elementary computer science theory. That's a big difference. I'm sorry if my initial comment came across as too harsh, but given the situation, your answer is very inefficient. This is not a personal comment, I don't even know you. And I'm not looking for design solutions, which I obviously can implement without help from SO.
That is okey. I am sorry too @Kartik. You have right.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.