Mask with numpy isin - python

I want to make a mask with numpy array. I've found a function, but it doesn't make what I want. Here is the code example:
np.isin([1,2,3,4,5,8,6,1,1],[1,2,3,5,1])
This code returns this:
array([ True, True, True, False, True, False, False, True, True], dtype=bool)
But I want the same output except the last value of the output array to be False. Because I need exact mask of the sequence ([1,2,3,5,1]) in this order and no longer than its length.

You can turn elements after certain amount of Trues to zero with:
mask[mask.cumsum() > 5] = False
# ^ length of the second array
import numpy as np
mask = np.isin([1,2,3,4,5,8,6,1,1],[1,2,3,5,1])
mask[mask.cumsum() > 5] = False
mask
# array([ True, True, True, False, True, False, False, True, False], dtype=bool)

Related

Finding indices where True values connect vertically and horizontally with numpy

I want to merge certain values that are numerically close.
In this example I'll look to merge anything that can be connected via a neighboring value with a difference less 2.
import numpy as np
a = np.arange(10)
a = np.delete(a, (3, 7))
matrix = np.abs(a.reshape(-1,1) - a)
matrix < 2
array([[ True, True, False, False, False, False, False, False],
[ True, True, True, False, False, False, False, False],
[False, True, True, False, False, False, False, False],
[False, False, False, True, True, False, False, False],
[False, False, False, True, True, True, False, False],
[False, False, False, False, True, True, False, False],
[False, False, False, False, False, False, True, True],
[False, False, False, False, False, False, True, True]])
Starting at the top left corner:
First move horizontal to find the last true value.
Then go downwards to find the last true value.
Repeat both until the square is found.
Cannot connect True values diagonally.
This would give you the first square that goes from [0,2] to [2,2].
The desired output of this example would be:
[[0, 2], [3, 5], [6, 7]]
Where the values indicate the beginning and end of the square. Is there a good way of doing this?
I'd prefer not to loop if possible.
So I've done this using np.diagonal as the basis for the logic.
bm = matrix < 2
endcoords = np.argwhere(bm[1:].diagonal() == False)
zers = np.zeros(endcoords.shape)
zers[1:] += endcoords[:-1] + 1
end = np.hstack((zers, endcoords))
end
array([[0., 2.],
[3., 5.]])
I know this excludes the last coordinate, which for my example doesn't give the 'correct' answer. This however, does give the right answer for my workflow as I'm chunking arrays together - so the last missing coordinate will be the first of my next array. It shouldn't be too hard to finagle the right answer from this anyways.

How to apply conditions for rows in a tensor where there is boolean values

I have the following tensor:
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
I applied conditions along the axis like below.
new_pred= []
if predictions == ([True,False,False]):
new_pred = torch.Tensor(0)
if predictions == ([False,False,True]):
new_pred = torch.Tensor(2)
if predictions == ([False,True,True]):
new_pred = torch.Tensor(2)
So I want the final output (new_pred) to be:
tensor([0, 2, 2, 0])
But I am getting a blank [] for the new_pred tensor. I think my logic must be flawed since nothing is getting stored in the new_pred. Can someone help me write this logic accurately?
The type of predictions is torch.Tensor while ([True, False, False]) is a list, first, you have to make sure both sides have the same type.
predictions == torch.tensor([True,False,False])
>>> tensor([[ True, True, True],
[False, True, False],
[False, False, False],
[True, True, True]])
Then, you are still comparing a 2d tensor to a 1d tensor, which is ambiguous in an if statement, an easy way to fix this would be to write a for loop, compare each row of the predictions to the conditions and append the result to the new_pred list. Note that you will be comparing two booleans tensors with the size of three, therefore, you have to make sure the result of the comparison is True for all of the cells.
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
conditions = torch.tensor([[True,False,False],
[False,False,True],
[False,True,True]])
new_predict = []
for index in range(predictions.size(0)):
if (predictions[index] == conditions[0]).all():
new_predict.append(0)
# ...
Alternatively, you can use slicing to achieve your expected result without any for loop.

Finding unique indices between arrays returned by numpy.where

I have two numpy arrays returned by the function numpy.where, like so:
A = numpy.where(img == 255)
B = numpy.where(img2 != 0)
I need to find number of unique coordinates in A and B. I initially contemplated using numpy.intersect1d to get the number of common indices, and subtract this from the total number of elements from both arrays. But these arrays are not 1-dimensional, so I'm not sure how to go about it.
Any suggestions how I can accomplish this?
Thanks
Numpy interprets the xor operator (^) as a logical xor, obeying:
X|Y|X^Y
0|0| 0
0|1| 1
1|0| 1
1|1| 0
So you can xor the boolean arrays:
(img == 255) ^ (img2 != 0)
An example:
>>> img == 255
array([[False, True, False],
[ True, False, False],
[False, False, False]])
>>> img != 0
array([[ True, True, True],
[ True, True, True],
[ True, True, True]])
>>> (img == 255) ^ (img2 != 0)
array([[False, False, True],
[ True, True, True],
[False, False, True]])
>>> ((img == 255) ^ (img2 != 0)).sum()
5
So there are 5 Trues in img or img2 that aren't in the other array at the same index.
update:
If you want the number of Trues in img or img2 (i.e. the same as the union of two sets of their True coordinates). Then use the logical or instead: |.

Finding False-True transitions in a numpy array

Given a numpy array:
x = np.array([False, True, True, False, False, False, False, False, True, False])
How do I find the number of times the values transitions from False to True?
For the above example, the answer would be 2. I don't want to include transitions from True to False in the count.
From the answers to How do I identify sequences of values in a boolean array?, the following produces the indices at which the values are about to change, which is not what I want as this includes True-False transitions.
np.argwhere(np.diff(x)).squeeze()
# [0 2 7 8]
I know that this can be done by looping through the array, however I was wondering if there was a faster way to do this?
Get one-off slices - x[:-1] (starting from the first elem and ending in second last elem) and x[1:] (starting from the second elem and going on until the end), then look for the first slice being lesser than the second one, i.e. catch the pattern of [False, True] and finally get the count with ndarray.sum() or np.count_nonzero() -
(x[:-1] < x[1:]).sum()
np.count_nonzero(x[:-1] < x[1:])
Another way would be to look for the first slice being False and the second one as True, the idea again being to catch that pattern of [False, True] -
(~x[:-1] & x[1:]).sum()
np.count_nonzero(~x[:-1] & x[1:])
I kind of like to use numpy method "roll" for this kind of problems...
"roll" rotates the array to left some step length : (-1,-2,...) or to right (1,2,...)
import numpy as np
np.roll(x,-1)
...this will give x but shifted one step to the left:
array([ True, True, False, False, False, False, False, True, False, False],
dtype=bool)
A False followed by a True can then be expressed as:
~x & np.roll(x,-1)
array([ True, False, False, False, False, False, False, True, False, False],
dtype=bool)

Numpy: Create a mask array to select rectangle

Is there a way to generate an array, masking a rectangular area, without the need to initialize an empty array first?
mask = np.zeros((10,10), dtype=bool)
mask[10/2:,10/2:] = True
Im looking for an numpy expression that would replace these two lines and generate mask
If you really, really want to have a one-liner, this is a possible way. But I'd say your original code is cleaner, clearer, and overall better...
>>> np.logical_and.outer(np.arange(10) >= 5, np.arange(6) >= 3)
array([[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True],
[False, False, False, True, True, True]], dtype=bool)
That can be done in one line:
mask = np.fromfunction(lambda i, j: (i >= 5) * (j >= 5), (10, 10), dtype=int)
but this turns out to be quite a bit slower than the original implementation. (It creates two arrays holding row and column indices).
You can use np.empty if you don't want to initialize the array and set the values manually. In this specific case, however, you might be better off using np.zeros or np.ones and flip the values for whichever is the smallest number of entries that you need to update.

Categories

Resources