-1

I'm trying to count the number of True values in a numpy.array until a False is reached.

For example, if you have

condition = np.array([True, True, True, False, 
    False, True, False, True, True, False, True])

Then the desired result would be

np.array([3, 2, 1, 0, 0, 1, 0, 2, 1, 0, 1])

Edit:

Numpy first occurrence of value greater than existing value is not what I'm asking because that's asking about the first time a condition is satisfied. I'm asking how many times in a row a condition is satisfied each time it is satisfied. Find first sequence item that matches a criterion also doesn't work because, again, I'm not asking about the first time a sequence satisfied a condition.

NewNameStat
  • 2,474
  • 1
  • 19
  • 26
  • Does this answer your question? [Numpy first occurrence of value greater than existing value](https://stackoverflow.com/questions/16243955/numpy-first-occurrence-of-value-greater-than-existing-value) – Acccumulation Jul 16 '21 at 22:25
  • There's also https://stackoverflow.com/questions/9868653/find-first-sequence-item-that-matches-a-criterion – Acccumulation Jul 16 '21 at 22:28
  • I think this can be done with a combination of `reversing`, `cumsum` and some sort of `reset` when False. But I'm not sure the potential time savings is worth the extra work. A simple iterative calculation starting from the end should work fast enough, and be easier to develop. – hpaulj Jul 16 '21 at 23:26
  • `np.hstack([np.array(list(gr)).cumsum()[::-1] for _, gr in groupby(condition)])` – Mustafa Aydın Jul 17 '21 at 12:53

4 Answers4

2
condition = np.array([True, True, True, False, 
    False, True, False, True, True, False, True])
    
r = []
c = 0

for x in reversed(condition):
  if x == False:
    c = 0
  else:
    c+=1
  r.append(c)
  
r.reverse()
print(np.array(r))

https://trinket.io/python3/a5bd54189b


a shorter version:

r = [0]
for x in reversed(condition):
  r.append(r[-1] + 1 if x else 0)

r.reverse()
r.pop()
print(np.array(r))
bakaDev
  • 367
  • 2
  • 7
1

Line by line to explain the calculation

import numpy as np                                                      

condition = np.array([True, True, True, False, False, True, False, True, True, False, True])                       

rvs = condition[::-1]   # Reverse the array order
rvs                                                                     
# array([ True, False,  True,  True, False,  True, False, False,  True,
        True,  True])

cum_rvs = rvs.cumsum()  # Cumulative sum of Trues                                         
cum_at_zero = (~rvs)*cum_rvs   # Cum where rvs is True set to zero                                         

cum_max = np.maximum.accumulate( cum_at_zero ) # Equivalent to cummax( cum_at_zero )
cum_max                                                               
# array([0, 1, 1, 1, 3, 3, 4, 4, 4, 4, 4])
  
result = cum_rvs - cum_max  # Use cum_max to adjust the cum_rvs down                        

result = result[::-1]  # Reverse the result order                                                
result                                                                  
# array([3, 2, 1, 0, 0, 1, 0, 2, 1, 0, 1])

Or in more condensed form:

rvs = condition[::-1]                                                   
cum_rvs = rvs.cumsum()

result = ( cum_rvs - np.maximum.accumulate((~rvs)*cum_rvs ))[::-1]   
            

                  
Tls Chris
  • 3,564
  • 1
  • 9
  • 24
0
import itertools
condition = np.array([True, True, True, False, False, True, False, True, True, False, True])
group_list = [list(g) for _, g in itertools.groupby(enumerate(condition), key = lambda x: x[-1])]
temp = 0
ans = []
for item in group_list:
    if item[0][1]:
        for i in range(len(item)):
            ans.append(len(item) - (item[i][0] - temp))
        temp += len(item)
    else:
        for i in range(len(item)):
            ans.append(0)
        temp += len(item)
print(ans)  
>>> [3, 2, 1, 0, 0, 1, 0, 2, 1, 0, 1]      
Ricardo
  • 691
  • 3
  • 11
0

You actually can do this comprehensively with like two lines of code, and without ext libs:

false_indices = [np.where(condition[j:] == False)[0] for j in range(len(condition))]

result = np.array([arr[0] if arr.size != 0 else int(condition[-1]) for arr in result])

It could even be a one-liner if it wasn't for the last bool in conditions which would raise an IndexError.

Max Shouman
  • 1,333
  • 1
  • 4
  • 11