Reputation: 379
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
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
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
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