Reputation: 7108
I'm using Python 2.7 and NumPy to work on big arrays of boolean values.
I have an array A, that is something like this:
>>> A
array([[[False, False, True, True, True],
[False, False, False, True, True],
[False, False, True, True, True],
[False, False, False, True, True],
[False, False, False, False, True]],
[[False, True, True, True, True],
[False, True, True, True, True],
[False, False, True, True, True],
[False, True, True, True, True],
[False, False, True, True, True]]])
I have to turn it in a boolean array like this:
>>> B
array([[[True, False, True, True, True],
[True, True, False, True, True],
[True, False, True, True, True],
[True, True, False, True, True],
[True, True, True, False, True]],
[[False, True, True, True, True],
[False, True, True, True, True],
[True, False, True, True, True],
[False, True, True, True, True],
[True, False, True, True, True]]])
So the idea is that the last False
value of each row should remain and any other value should become True
.
I need to create it in order to use it as a mask for another array.
Is there a way to do it with NumPy without using for
loops (that are quite slow)?
Upvotes: 3
Views: 1054
Reputation: 176730
Here is one way that works for your array (and also works for arrays with more mixed up rows such as [F, T, T, F, T]
too):
>>> x = 4 - np.argmin(A[:,:,::-1], axis=2)[:,:,np.newaxis]
>>> (np.arange(5) * np.ones_like(A)) != x
array([[[ True, False, True, True, True],
[ True, True, False, True, True],
[ True, False, True, True, True],
[ True, True, False, True, True],
[ True, True, True, False, True]],
[[False, True, True, True, True],
[False, True, True, True, True],
[ True, False, True, True, True],
[False, True, True, True, True],
[ True, False, True, True, True]]], dtype=bool)
Explanation:
Flip the array A
on axis=2
and use argmin
across that axis to get the index of the first False
value.
We need to know the index of the last occurrence of False
in A
(not the first occurrence in the flipped array). This is the value of the depth of the array (i.e. 5), minus 1, minus the index found in the previous step.
Make this new array of indices compatible with A
by adding a new axis (axis=2
). Call this new array of indices x
.
Construct an array of the same dimensions as A
where each row of axis=2
is np.arange(5)
. The desired boolean array is found by testing for inequality of this constructed array with x
.
Upvotes: 3
Reputation: 1740
You could also use the xor operator ^
for that purpose. Simply "leftshift" the array by one and add True
values to the right and then xor the new and the old array:
A = np.array([[False, False, True, True, True],
[False, False, False, True, True],
[False, False, True, True, True],
[False, False, False, True, True],
[False, False, False, False, True]])
X = np.hstack((A[:,1:],
np.array(np.ones((A.shape[0], 1)), dtype=np.bool))))
>>> array([[False, True, True, True, True],
[False, False, True, True, True],
[False, True, True, True, True],
[False, False, True, True, True],
[False, False, False, True, True]])
np.invert(A ^ X)
>>> array([[True, False, True, True, True],
[True, True, False, True, True],
[True, False, True, True, True],
[True, True, False, True, True],
[True, True, True, False, True]])
This only works if all False
values are left and followed by only True
values.
Upvotes: 3
Reputation: 8709
This is a simple problem. You need to select each row. Find the positions of False using np.where() and place True in those positions except the last one denoted by index [-1]. This is done in the code given below:
>>> import numpy as np
>>> A=np.array([[[False, False, True, True, True],
[False, False, False, True, True],
[False, False, True, True, True],
[False, False, False, True, True],
[False, False, False, False, True]],
[[False, True, True, True, True],
[False, True, True, True, True],
[False, False, True, True, True],
[False, True, True, True, True],
[False, False, True, True, True]]])
>>> for mat in A:
opmat=[]
for arr in mat:
index=np.where(arr==False)
arr[index[0][:-1]]=True
opmat.append(arr)
out.append(opmat)
>>> out=np.array(out)
>>> out
array([[[ True, False, True, True, True],
[ True, True, False, True, True],
[ True, False, True, True, True],
[ True, True, False, True, True],
[ True, True, True, False, True]],
[[False, True, True, True, True],
[False, True, True, True, True],
[ True, False, True, True, True],
[False, True, True, True, True],
[ True, False, True, True, True]]], dtype=bool)
Upvotes: 0
Reputation: 49816
If you invert the array, you can use numpy.nonzero
to find all the (originally) false entries, then take the last one in each row from that. You can then use that to construct your mask array.
Upvotes: 1