KoKo
KoKo

Reputation: 379

Looping through a numpy array

I have a 5 by 10 array and I want to flip a bit if a random number is greater than 0.9. However, this only works for the first row of the array and it doesn't get to the second and subsequent row. I replaced the bits with 3 and 4 so i can easily see if the flipping occurs. I have been getting results that look like this.

[[3 1 1 1 4 1 3 1 0 1]
 [1 1 0 0 1 0 1 1 1 0]
 [1 0 1 0 1 0 1 1 1 1]
 [0 0 1 0 1 1 0 1 1 1]
 [0 1 1 0 0 0 0 1 1 1]]

Please help me figure out where I'm wrong.


from random import random
RM =  np.random.randint(0,2, size=(5,10))
print(RM)
for k in range(0, RM.shape[0]):
    for j in range(0, RM.shape[1]):
        A  = random()
        if A > 0.9:
            if RM[k,j] == 0:
                np.put(RM, [k,j], [3]) 
                print("k1",k)
                print("j1", j)
            else:
                np.put(RM, [k,j], [4])  
                print("k2", k)
        else: 
            continue

print(RM)

Upvotes: 1

Views: 136

Answers (3)

Valdi_Bo
Valdi_Bo

Reputation: 30971

To iterate over a Numpy array, a convenient (and recommended) tool is nditer.

If you want to change values of the iterated array, op_flags=['readwrite'] should be passed.

To have access to the indices of the current element, in case of a multi-dimension array, flags=['multi_index'] should be passed.

Below you have example code, which also prints indices in each case the current element has been flipped.

To check how it operates, I added a printout of RM, both before and after the loop.

np.random.seed(0)
RM = np.random.randint(0, 2, size=(5, 10))
print('Before:')
print(RM, '\n')
with np.nditer(RM, op_flags=['readwrite'], flags=['multi_index']) as it:
    for x in it:
        A  = np.random.random()
        if A > 0.9:
            x[...] = 1 - x  # Flip
            print(f'Flip: <{it.multi_index}>,  {A:.3f}')
print('\nAfter:')
print(RM)

To get repeatable result, I added np.random.seed(0) (remove it in the target version).

With the above seeding, I got the following result:

Before:
[[0 1 1 0 1 1 1 1 1 1]
 [1 0 0 1 0 0 0 0 0 1]
 [0 1 1 0 0 1 1 1 1 0]
 [1 0 1 0 1 1 0 1 1 0]
 [0 1 0 1 1 1 1 1 0 1]] 

Flip: <(0, 2)>,  0.945
Flip: <(1, 3)>,  0.944
Flip: <(2, 7)>,  0.988
Flip: <(4, 5)>,  0.976
Flip: <(4, 7)>,  0.977

After:
[[0 1 0 0 1 1 1 1 1 1]
 [1 0 0 0 0 0 0 0 0 1]
 [0 1 1 0 0 1 1 0 1 0]
 [1 0 1 0 1 1 0 1 1 0]
 [0 1 0 1 1 0 1 0 0 1]]

Compare elements indicated as flipped, in "Before" and "After" sections, to confirm that the above code does its job. Check also that no other element has been changed.

A bit tricky element in the above code is x[...] = 1 - x. Note that 1 - x part reads the current value (so far it is OK). But if you attempted to save anything to x, writing x =, then you would break the link to the source array element. In this case x would point to the new value, but not to the current array element.

So in order not to break this link, just x[...] = notation is needed.

Upvotes: 0

warped
warped

Reputation: 9482

Looking at the documentation of np.put

numpy.put(a, ind, v, mode='raise')[source]
Replaces specified elements of an array with given values.

under Examples:

a = np.arange(5)
np.put(a, [0, 2], [-44, -55])
a
array([-44,   1, -55,   3,   4])

So, if you feed a list to the function, it replaces multiple values in the flattened array.

To make your loop work, simply assigning the values to the array should work:

from random import random
RM =  np.random.randint(0,2, size=(5,10))
print(RM)
for k in range(0, RM.shape[0]):
    for j in range(0, RM.shape[1]):
        A  = random()
        if A > 0.9:
            if RM[k,j] == 0:
                RM[k,j]=3 
                print("k1",k)
                print("j1", j)
            else:
                RM[k,j] =4  
                print("k2", k)
        else: 
            continue

Upvotes: 1

StupidWolf
StupidWolf

Reputation: 46898

Most likely you don't need the iteration. The flips are independent, you can generate the probabilities at one go, and just flip:

np.random.seed(100)
RM =  np.random.randint(0,2, size=(5,10))

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

alpha = np.random.uniform(0,1,(5,10))
np.round(alpha,2)

array([[0.49, 0.4 , 0.35, 0.5 , 0.45, 0.09, 0.27, 0.94, 0.03, 0.04],
       [0.28, 0.58, 0.99, 0.99, 0.99, 0.11, 0.66, 0.52, 0.17, 0.94],
       [0.24, 1.  , 0.58, 0.18, 0.39, 0.19, 0.41, 0.59, 0.72, 0.49],
       [0.31, 0.58, 0.44, 0.36, 0.32, 0.21, 0.45, 0.49, 0.9 , 0.73],
       [0.77, 0.38, 0.34, 0.66, 0.71, 0.11, 0.13, 0.46, 0.16, 0.96]])

RM[alpha>0.9] = abs(1-RM[alpha>0.9])
RM

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

Upvotes: 1

Related Questions