I have an m-by-n numpy array, and I'd like to add 1.0 to all entries [i, j] when (i + j) % 2 == 0, i.e., "to every other square".
I could of course simply iterate over the fields
import numpy as np
a = np.random.rand(5, 4)
for i in range(a.shape[0]):
    for j in range(a.shape[1]):
        if (i + j) % 2 == 0:
            a[i, j] += 1.0
but needless to say this is really slow.
Any idea of how to improve on this?
You can easily do the operation in two steps, like
import numpy as np
a = np.zeros((5, 14))
# Even rows, odd columns
a[::2, 1::2] += 1
# Odd rows, even columns
a[1::2, ::2] += 1
print a
                        Here's one way using NumPy broadcasting -
a[(np.arange(a.shape[0])[:,None] + np.arange(a.shape[1]))%2==0] += 1
Explanation : We basically create two arrays that are equivalent of the i-th and j-th iterators. Let's call them I and J.
I = np.arange(a.shape[0])
J = np.arange(a.shape[1])
Now, to perform an operation between all possible i and j, we create extend I to 2D by pushing its elements into the first axis and thus creating singleton dimension along its second axis.
Figuratively, the effect of broadcasting could be put like this :
    I[:,None] : M , 1
            J : 1 , N
I[:,None] + J : M,  N
Thus, the final setting would be -
a[(I[:,None] + J)%2==0] += 1
To put it other way with the intention to avoid comparing with 0 and directly use mod-2 which would be essentially 0 or 1 -
a += (np.arange(a.shape[0])[:,None]-1 + np.arange(a.shape[1]))%2
One can also use np.ix_ to process odd and then even rows for setting, like so -
a[np.ix_(np.arange(0,a.shape[0],2),np.arange(0,a.shape[1],2))] += 1
a[np.ix_(np.arange(1,a.shape[0],2),np.arange(1,a.shape[1],2))] += 1
                        One can build a mask for "every other" element, and apply the addition on the mask.
# Create mask
m00 = np.zeros(a.shape[0], dtype=bool)
m00[0::2] = True
m01 = np.zeros(a.shape[1], dtype=bool)
m01[0::2] = True
m0 = np.logical_and.outer(m00, m01)
m10 = np.zeros(a.shape[0], dtype=bool)
m10[1::2] = True
m11 = np.zeros(a.shape[1], dtype=bool)
m11[1::2] = True
m1 = np.logical_and.outer(m10, m11)
m = np.logical_or(m0, m1)
a[m] += 1
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With