Reputation: 115
I am trying to perform some conditional checks on numpy arrays and my code right now is not very pythonic. Can someone suggest more efficient ways to write the code below ?
eps = 1.0e-04 #Fill in gaps in the surfaces##################################### for i in range(nrows): for j in range(ncols): if (ibound[i,j] == 1 and fabs(h[i,j]-nodata) <= eps): h[i,j] = L1TopOld[i,j]
Upvotes: 1
Views: 458
Reputation: 778
You only need to proceed the vectorial way:
cond = (ibound == 1) & (np.fabs(h - nodata) <= eps)
h[cond] = L1TopOld[cond]
Let's see an example (I am using the one proposed in the previous comment):
>>> import numpy as np
>>> h = np.random.random((3, 4))
>>> nodata = 10
>>> h.flat[[2, 3, 4, 7, 8, 9]] = nodata
>>> ibound = np.random.randint(0, 2, (3, 4))
>>> L1TopOld = np.ones((3, 4)) * 5
>>> eps = 0.01
>>> ibound
array([[0, 0, 1, 0],
[0, 0, 1, 1],
[1, 1, 1, 1]])
>>> L1TopOld
array([[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.]])
>>> h
array([[ 0.89332453, 0.71094897, 10. , 10. ],
[ 10. , 0.47419211, 0.50206745, 10. ],
[ 10. , 10. , 0.71388832, 0.84379527]])
>>> cond = (ibound == 1) & (np.fabs(h - nodata) <= eps)
>>> cond
array([[False, False, True, False],
[False, False, False, True],
[ True, True, False, False]], dtype=bool)
>>> h[cond] = L1TopOld[cond]
>>> h
array([[ 0.89332453, 0.71094897, 5. , 10. ],
[ 10. , 0.47419211, 0.50206745, 5. ],
[ 5. , 5. , 0.71388832, 0.84379527]])
Yours
Upvotes: 1
Reputation: 23743
If you want to modify the original array:
import numpy as np
eps = .01
nodata = 10
h = np.array([[0.1382408, 0.7718657, 10. , 10. ],
[ 10. , 0.5595833, 0.83703255, 10. ],
[ 10. , 10. , 0.79473842, 0.91882331]])
h.flat[[2,3,4,7,8,9]] = 10
ibound = np.array([[0, 1, 1, 0],
[0, 1, 1, 0],
[0, 1, 0, 1]])
L1TopOld = np.array([[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.]])
Create a logical mask with your condition:
mask = (ibound == 1) & (abs(h - nodata) <= eps)
Modify the array using boolean indexing
h[mask] = L1TopOld[mask]
print h
[[ 0.1382408 0.7718657 5. 10. ]
[ 10. 0.5595833 0.83703255 10. ]
[ 10. 5. 0.79473842 0.91882331]]
Upvotes: 1
Reputation: 352959
You can use np.where
. First, let's make some toy data (BTW, it helps if you do this part of it yourself):
>>> h = np.random.random((3,4))
>>> nodata = 10
>>> h.flat[[2,3,4,7,8,9]] = 10
>>> ibound = np.random.randint(0,2,(3,4))
>>> L1TopOld = np.ones((3,4))*5
>>> h
array([[ 0.1382408 , 0.7718657 , 10. , 10. ],
[ 10. , 0.5595833 , 0.83703255, 10. ],
[ 10. , 10. , 0.79473842, 0.91882331]])
>>> ibound
array([[0, 1, 1, 0],
[0, 1, 1, 0],
[0, 1, 0, 1]])
>>> L1TopOld
array([[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.],
[ 5., 5., 5., 5.]])
>>> eps = 0.01
Now we can decide which ones we want to patch:
>>> ibound & (abs(h-nodata) <= eps)
array([[0, 0, 1, 0],
[0, 0, 0, 0],
[0, 1, 0, 0]])
and use this to tell np.where
where we want to switch:
>>> np.where(ibound & (abs(h - nodata) <= eps), L1TopOld, h)
array([[ 0.1382408 , 0.7718657 , 5. , 10. ],
[ 10. , 0.5595833 , 0.83703255, 10. ],
[ 10. , 5. , 0.79473842, 0.91882331]])
As pointed out in the comments, this assumes that ibound
is a mask consisting only of 0 and 1. If you really only want to change the cases where ibound == 1
(and not 2, for example), that's easy too:
>>> np.where((ibound == 1) & (abs(h - nodata) <= eps), L1TopOld, h)
array([[ 0.1382408 , 0.7718657 , 5. , 10. ],
[ 10. , 0.5595833 , 0.83703255, 10. ],
[ 10. , 5. , 0.79473842, 0.91882331]])
(which gives the same answer here because 0 and 1 were the only numbers in ibound
.)
Upvotes: 2