Related
Consider the following 2d array:
>>> A = np.arange(2*3).reshape(2,3)
array([[0, 1, 2],
[3, 4, 5]])
>>> b = np.array([1, 2])
I would like to get the following mask from A as row wise condition from b as an upper index limit:
>>> mask
array([[True, False, False],
[True, True, False]])
Can numpy do this in a vectorized manner?
You can use array broadcasting:
mask = np.arange(A.shape[1]) < b[:,None]
output:
array([[ True, False, False],
[ True, True, False]])
Another possible solution, based on the idea that the wanted mask corresponds to a boolean lower triangular matrix:
mask = np.tril(np.ones(A.shape, dtype=bool))
Output:
array([[ True, False, False],
[ True, True, False]])
This question already has an answer here:
Replace 2D numpy array elements based on 2D indexes [duplicate]
(1 answer)
Closed 12 months ago.
Suppose I have a boolean numpy array, and I perform np.argwhere() on it. Is there any way to easily and efficiently do the reverse operation? In other words, given the final shape of a, and the results of argwhere(), how can I find a? I've tried to use the argwhere results together with an array full of False, but can't figure out how to use to do it. Maybe somehow use np.where()?
>>> a = np.array([[False, True, False, True, False],
[False, False, True, False, False]])
>>> results = np.argwhere(a)
>>> results
array([[0, 1],
[0, 3],
[1, 2]], dtype=int64)
>>> recover_a = np.full(shape=a.shape, fill_value=False) # I am
>>> # guessing I could start here then do something...
Use results columns as indices to update the value in recover_a:
recover_a[results[:,0], results[:,1]] = True
recover_a
# array([[False, True, False, True, False],
# [False, False, True, False, False]])
In [233]: a = np.array([[False, True, False, True, False], [False, False, True,
...: False, False]])
In [234]: np.argwhere(a)
Out[234]:
array([[0, 1],
[0, 3],
[1, 2]])
In [235]: np.nonzero(a)
Out[235]: (array([0, 0, 1]), array([1, 3, 2]))
argwhere is just the np.transpose(np.nonzero(a)). One is a tuple of arrays, the other a 2d array with those arrays arranged as columns.
The nonzero/where result is better for indexing, since it is a tuple of indices.
In [236]: res = np.zeros(a.shape, bool)
In [237]: res[np.nonzero(a)] = True
In [238]: res
Out[238]:
array([[False, True, False, True, False],
[False, False, True, False, False]])
In [239]: a[np.nonzero(a)]
Out[239]: array([ True, True, True])
Suppose i have a boolean array with shape (nrows,ncols). True represents that i have a defined value (real number) and False represents an undefined / (not of interest) values.
Im trying to figure out an efficient way to extract the rows and cols of both the boundary and the interior, for example if i had the floowing boolean array, where im marking the boundaries by red and the interior by green:
then a desired output would be (the position of the green Trues):
interior = [(2,3), (2,4)]
We can assume that the interior is always connected.
Using np.where(array == False)[0], i get the indices of the Falses, but how to go from here to the boundaries indices and then to the interior ? I can ofcourse loop through each boolean and check if any of the neighbours is False, if no, then its an interior.
Any tips on how to do this efficiently without looping? Another example to be clear:
desired output:
interior = [(2,3) , (2,4) , (3,3) , (3,4) , (3,5) , (4,3), (4,4), (4,5)]
The output can be a boolean array as well, containing Trues in interior positions, False otherwise. It does not matter. Thanks in advance.
Approach #1
We can use 2D convolution -
from scipy.signal import convolve2d
def interior_indices(a):
kernel = np.ones((3,3),dtype=int)
return np.argwhere(convolve2d(a,kernel,'same')==9)
Sample runs -
In [44]: a1
Out[44]:
array([[False, False, False, False, False, False, False, False],
[ True, True, True, True, True, True, False, False],
[False, True, True, True, True, True, True, False],
[False, False, True, True, True, True, False, False]])
In [45]: interior_indices(a1)
Out[45]:
array([[2, 3],
[2, 4]])
In [46]: a2
Out[46]:
array([[False, False, False, False, False, False, False, False],
[False, True, True, True, True, True, False, False],
[False, True, True, True, True, True, True, False],
[False, False, True, True, True, True, True, False],
[False, False, True, True, True, True, True, False],
[False, True, True, True, True, True, True, False],
[False, False, False, True, True, False, False, False]])
In [47]: interior_indices(a2)
Out[47]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Approach #2
Alternatively, with uniform-filter -
In [61]: from scipy.ndimage import uniform_filter
In [62]: np.argwhere(uniform_filter(a1,mode='constant'))
Out[62]:
array([[2, 3],
[2, 4]])
In [63]: np.argwhere(uniform_filter(a2,mode='constant'))
Out[63]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Approach #3
And with binary-erosion -
In [72]: from scipy.ndimage.morphology import binary_erosion
In [73]: kernel = np.ones((3,3),dtype=bool)
In [74]: np.argwhere(binary_erosion(a1,kernel))
Out[74]:
array([[2, 3],
[2, 4]])
In [75]: np.argwhere(binary_erosion(a2,kernel))
Out[75]:
array([[2, 3],
[2, 4],
[3, 3],
[3, 4],
[3, 5],
[4, 3],
[4, 4],
[4, 5]])
Found a way ! If its too trivial, vote delete :)
#data: the boolean array
d0 = data[1:-1, 2:]
d1 = data[:-2, 2:]
d2 = data[:-2, 1:-1]
d3 = data[:-2, :-2]
d4 = data[1:-1, :-2]
d5 = data[2:, :-2]
d6 = data[2:, 1:-1]
d7 = data[2:, 2:]
interior = np.where(d0 & d1 & d2 & d3 & d4 & d5 & d6 & d7, True, False)
I have a numpy matrix and want to compare every columns to a given array, like:
M = np.array([1,2,3,3,2,1,1,3,2]).reshape((3,3)).T
v = np.array([1,2,3])
Now I want to compare every columns of M with v, i.e. I want a matrix with the first column consisting of True, True, True. A second saying False, True, False. A third True, False, False.
How do I achieve this?
Thanks!
Use broadcasted comparison:
>>> M == v[:, None]
array([[ True, False, True],
[ True, True, False],
[ True, False, False]])
You might consider using np.equal column-wise:
np.array([np.equal(col, v) for col in M.T]).T
it compares the elements of two numpy arrays element-wise. The M.T makes for loop to pop your original M columns as one-dimensional arrays and the final transpose is needed to reverse it.
Here the equal/not_equal functions are described.
Alternatively, you could match each row in the matrix with the given vector using np.apply_along_axis
>>> M
array([[1, 3, 1],
[2, 2, 3],
[3, 1, 2]])
>>> v
array([1, 2, 3])
>>> np.apply_along_axis(lambda x: x==v, 1, M)
array([[ True, False, False],
[False, True, True],
[False, False, False]], dtype=bool)
I'm trying to find the row in which a 2d array appears in a 3d numpy ndarray. Here's an example of what I mean. Give:
arr = [[[0, 3], [3, 0]],
[[0, 0], [0, 0]],
[[3, 3], [3, 3]],
[[0, 3], [3, 0]]]
I'd like to find all occurrences of:
[[0, 3], [3, 0]]
The result I'd like is:
[0, 3]
I tried to use argwhere but that unfortunately got me nowhere. Any ideas?
Try
np.argwhere(np.all(arr==[[0,3], [3,0]], axis=(1,2)))
How it works:
arr == [[0,3], [3,0]] returns
array([[[ True, True],
[ True, True]],
[[ True, False],
[False, True]],
[[False, True],
[ True, False]],
[[ True, True],
[ True, True]]], dtype=bool)
This is a three dimensional array where the innermost axis is 2. The values at this axis are:
[True, True]
[True, True]
[True, False]
[False, True]
[False, True]
[True, False]
[True, True]
[True, True]
Now with np.all(arr==[[0,3], [3,0]], axis=2) you are checking if both elements on a row are True and its shape will be reduced to (4, 2) from (4, 2, 2). Like this:
array([[ True, True],
[False, False],
[False, False],
[ True, True]], dtype=bool)
You need one more step of reducing as you want both of them to be the same (both [0, 3] and [3, 0]. You can do it either by reducing on the result (now the innermost axis is 1):
np.all(np.all(test, axis = 2), axis=1)
Or you can also do it by giving a tuple for the axis parameter to do the same thing step by step (first innermost, then one step higher). The result will be:
array([ True, False, False, True], dtype=bool)
The 'contains' function in the numpy_indexed package (disclaimer: I am its author) can be used to make queries of this kind. It implements a solution similar to the one offered by Saullo.
import numpy_indexed as npi
test = [[[0, 3], [3, 0]]]
# check which elements of arr are present in test (checked along axis=0 by default)
flags = npi.contains(test, arr)
# if you want the indexes:
idx = np.flatnonzero(flags)
In you can use np.in1d after defining a new data type which will have the memory size of each row in your arr. To define such data type:
mydtype = np.dtype((np.void, arr.dtype.itemsize*arr.shape[1]*arr.shape[2]))
then you have to convert your arr to a 1-D array where each row will have arr.shape[1]*arr.shape[2] elements:
aView = np.ascontiguousarray(arr).flatten().view(mydtype)
You are now ready to look for your 2-D array pattern [[0, 3], [3, 0]] which also has to be converted to dtype:
bView = np.array([[0, 3], [3, 0]]).flatten().view(mydtype)
You can now check the occurrencies of bView in aView:
np.in1d(aView, bView)
#array([ True, False, False, True], dtype=bool)
This mask is easily converted to indices using np.where, for example.
Timings (updated)
THe following function is used to implement this approach:
def check2din3d(b, a):
"""
Return where `b` (2D array) appears in `a` (3D array) along `axis=0`
"""
mydtype = np.dtype((np.void, a.dtype.itemsize*a.shape[1]*a.shape[2]))
aView = np.ascontiguousarray(a).flatten().view(mydtype)
bView = np.ascontiguousarray(b).flatten().view(mydtype)
return np.in1d(aView, bView)
The updated timings considering #ayhan comments showed that this method can be faster the np.argwhere, but the different is not significant and for large arrays like below, #ayhan's approach is considerably faster:
arrLarge = np.concatenate([arr]*10000000)
arrLarge = np.concatenate([arrLarge]*10, axis=2)
pattern = np.ascontiguousarray([[0,3]*10, [3,0]*10])
%timeit np.argwhere(np.all(arrLarger==pattern, axis=(1,2)))
#1 loops, best of 3: 2.99 s per loop
%timeit check2din3d(pattern, arrLarger)
#1 loops, best of 3: 4.65 s per loop