Finding False-True transitions in a numpy array - python

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)

Related

Finding a specific pattern in a boolean array

I am working on a project and am getting stuck on the following bit : I have a boolean array and I would like to determine if a specific pattern is present in this array.
For example, let's imagine I have this boolean array : [True, False, False, True, False, False, True, False, True, True, True] and I would like to know if it contains the following pattern [False, False, True, False].
My first idea was to loop through all values of the boolean array, define a variable that counts the number of consecutive "False" then loops again to find if "True" is following that sequence, etc... But it seems a bit tedious and I imagine there is a better way to do this...
Any advice would be very welcomed !
Thank you
One way would be to convert the array to a string of f and t characters, then use string search to find the desired pattern. For example:
def bool_list_to_str(bool_list):
return ''.join('ft'[i] for i in bool_list)
You can call this function to convert both your array and your search pattern to strings. Then you can use s.find(p) to search for pattern p in string s.
Note that this uses one character per bool value, so the string will have the same length as the bool list, and the indices will match. It also uses a minimal amount of string memory.
You can join them as string and check for substring:
super_list = [True, False, False, True, False, False, True, False, True, True, True]
sub_list = [False, False, True, False]
super_list_as_str = ''.join(map(str, super_list))
sub_list_as_str = ''.join(map(str, sub_list))
if sub_list_as_str in super_list_as_str:
print('Sub string')
I am starting with programming then my code is not optimize. But it's very easy to understand:
1.- Create a list with all the combinations of the array with lenght n
2.- Make a comparision of the pattern with the list you have create.
# a is the array you want to check with
a = [True, False, False, True, False, False, True, False, True, True, True]
# b is the array you want to check
b = [False, True, False, False]
# patterns is the list with all the patterns in the array
patterns = []
for i in range(len(a)-(len(b)-1)):
patterns.append((a[i:(len(b)+i)]))
# Check if b is in the list you have create.
b in patterns

Getting True values in a boolean list from indices - python

How do I compute the inverse of what is described here: Getting indices of True values in a boolean list ?
That above link always comes up when I try searching for "how to obtain the true values in a boolean list from integer indices," but it gives me the indices from the true values in a boolean list, which is the inverse of what I want...
For example, from:
t = [4, 5, 7]
count = 16
I want to obtain:
[False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
The values are all 0 indexed, as expected with Python.
I'm guessing that my question is a duplicate, but it's so annoying to not be able to find what I'm looking for every time I try to remember how to do this operation, I decided to ask a new question so my Google search will hopefully bring up this post next time.
You can use a list comprehension. I recommend you turn t into a set for O(1) lookup:
t_set = set(t)
res = [i in t_set for i in range(count)]
Use a list comprehension with conditions:
print([True if i in t else False for i in range(count)])
Shorter:
print([i in t else False for i in range(count)])
How about this:
In [6]: holderplace =[False for i in range(count)]
In [7]: for i in t:
...: holderplace[i-1]=True
...:
In [8]: holderplace
Out[8]:
[False,
False,
False,
True,
True,
False,
True,
False,
False,
False,
False,
False,
False,
False,
False,
False]
In [9]:
You could also try using map():
list(map(lambda x: x in t, range(count)))
# [False, False, False, False, True, True, False, True, False, False, False, False, False, False, False, False]
It might also be worth converting t to a set, since lookup is O(1) instead of O(N).
You could also use __contains__():
list(map(t.__contains__, range(count)))

Mask with numpy isin

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)

Python - Apply an conditional function (intersection) to every element of a list

I have a python list of ints, a. I also have another list, b, which is a tuple of 2 values (c, d). I need to see if any elements of a have values that are between any of the tuple elements of b.
I think there is a way to do this using map(), but I can't figure out how to pass in the values of my tuple list.
For example, my data structure looks like:
a = [1, 2, 3, 4, 5, 6, 7]
b = [(12,14), (54, 78), (2,3), (9,11)]
I am trying to find out if any of the elements in a have values between any of the tuple elements of b. In the above case, 2 and 3 (from a) are inside (inclusive) of the tuple (2,3) in b. So my final answer would be True.
Does anyone have any idea how to do this in a performat way? Right now, I am looping through each element of a and then looping through each element of b. This is ok for small amounts of data, but my arrays are quite large and this step takes way to long.
dId you want this?
[c in range(k[0], k[1]+1) for c in a for k in b]
returns:
[False, False, False, False, # 1 is in any ofthe tuple range in b?
False, False, True, False, # 2 is in any of the tuple range in b?
False, False, True, False, # etc. etc....
False, False, False, False,
False, False, False, False,
False, False, False, False,
False, False, False, False] # searches for each element in a within the range specified by the tuple elements in b
If you wanted to do something else like check every element in a using each element of b first then swap the order of the fors:
[c in range(k[0], k[1]+1) for k in b for c in a]
returns:
[False, False, False, False, False, False, False, // is b[0] range covers 1-7?
False, False, False, False, False, False, False, // etc. etc.
False, True, True, False, False, False, False,
False, False, False, False, False, False, False]
I assumed this is what you didn't want....but thought I would post it to you anyway
If the (c, d) values restricted to a certain range (say 0-100), you could calculate a boolean array of allowed values, and compare a against that with a simple index lookup.
If you the values are not restricted or the range would be too large, put the values of b into a sorted data structure. Then you can look up a against that quickly, without needing to go through the whole list every time. While building this lookup data structure, you would have to look out for overlapping ranges, and merge them.
If you sort first you can avoid checking every value in a against every tuple in b. The tuples that have already been checked against lower values of a can be discarded, which will make the check much faster.
def check_value_in_ranges(a, b):
a = sorted(set(a))
b = sorted(set(b), reverse=True)
lower, upper = b.pop()
for value in a:
while value >= lower:
if value <= upper:
return True
elif not b:
return False # no tuples left to check against
lower, upper = b.pop()
return False # no values of a left to check
I think this works whether the tuples are overlapping or not - check here.

How do I find what index a True value is located at in an array contaning True and False values?

I have an np.array with True and False values in it. Something along the lines of this:
full=[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, False, False,
False, False, False, False, False, False, False, False, False]
There is a true value at the 24th position. I know that
b = np.where(full)
will print out something like this
(array([24]),)
but I am only interested in the number 24. Assuming that this True value can be at any place in the full array and that there can even be more than one True value in full, how do I retrieve the numbers in b?
edit: Trying to be more specific. Basically I am trying to take the value from b and put it into another np.array. If I enter b into a 1d array like so:
oar[b]
because b is not a number it sends back an error.
Also, just to reiterate, full is a numpy array and can have all true, no true, or multiple true values.
you can use argmax(arr) for the index of the first True value.
As pointed out by #Alok, if the result is zero you must then check if the first element of arr is False.

Categories

Resources