How to count the number of times a continuous condition is true?

Viewed 114

Each row of the A column is compared with the A value when the COND column was True last time, if it is less than it, the condition is satisfied, and the count is accumulated. Stop counting until greater than or equal to.

Input:

import pandas as pd
A=[28,30,15,25,24,13,31,19,20,11,19,21]
COND=[False,True,False,False,False,False,False,False,True,False,False,False]
df=pd.DataFrame({'A':A,'COND':COND})

Expected Output

    A   COND    expected
0   28  FALSE   0
1   30  TRUE    0
2   15  FALSE   1
3   25  FALSE   2
4   24  FALSE   3
5   13  FALSE   4
6   31  FALSE   0
7   19  FALSE   0
8   20  TRUE    0
9   11  FALSE   1
10  19  FALSE   2
11  21  FALSE   0
2 Answers

In order to achieve this result, you need to iterate over the lists to determine the outputted values.

Start by assigning some base variables:

expected = []
lastTrue = None
count = 0

These will be modified throughout the loop. Next, loop through and test for each condition.

Loop through the numbers:

for i in range(len(A)):
    num = A[i]

Test for if the condition is True; if it is, save the number and reset the count:

if COND[i]:  # If True, save the number and reset count
    lastTrue = num
    count = 0

Check for if a True value has been found yet:

elif lastTrue is None:  # If haven't found a True value yet, pass
    pass

Test the number against the last true number to determine the output:

elif num < lastTrue:  # If less than the last True value, increment count
    count += 1
else:  # If larger than or equal to, reset count
    count = 0
    lastTrue = None

Add the current count to the list:

expected.append(count)

Now all you need to do is add the column and print the output.

Final code:

import pandas as pd
A=[28,30,15,25,24,13,31,19,20,11,19,21]
COND=[False,True,False,False,False,False,False,False,True,False,False,False]

expected = []
lastTrue = None
count = 0
for i in range(len(A)):
    num = A[i]
    if COND[i]:  # If True, save the number and reset count
        lastTrue = num
        count = 0
    elif lastTrue is None:  # If haven't found a True value yet, pass
        pass
    elif num < lastTrue:  # If less than the last True value, increment count
        count += 1
    else:  # If larger than or equal to, reset count
        count = 0
        lastTrue = None
    expected.append(count)

df=pd.DataFrame({'A':A,'COND':COND,'EXPECTED':expected})
print(df)

Output:

      A   COND  EXPECTED
 0   28  False         0
 1   30   True         0
 2   15  False         1
 3   25  False         2
 4   24  False         3
 5   13  False         4
 6   31  False         0
 7   19  False         0
 8   20   True         0
 9   11  False         1
 10  19  False         2
 11  21  False         0

This is an old question and you already have an answer. But I thought I add an answer from "within the Pandas framework" (i.e. avoiding explicit iteration over dataframe rows).

You could try:

df["Res"] = df.groupby(df["COND"].cumsum()).agg(
    Res=("COND", "cumcount"), A_cummax=("A", "cummax")
).assign(
    A_first=df["A"].where(df["COND"]).ffill().fillna(df["A"]),
    Res=lambda df: df["Res"].where(df["A_cummax"] <= df["A_first"], 0)
)["Res"]
  • df["COND"].cumsum() identifies the groups you want to address, so grouping over it is the first step.
  • Then add two columns via .agg(): (1) Res build by .cumcount() is almost the result you're looking for, but has to be adjusted a bit. (2) An auxiliary column A_cummax.
  • Afterwards add a second auxiliary column A_first that identifies the resp. first A-values. The dataframe now looks like:
        Res  A_cummax  A_first
    0     0        28     28.0
    1     0        30     30.0
    2     1        30     30.0
    3     2        30     30.0
    4     3        30     30.0
    5     4        30     30.0
    6     5        31     30.0
    7     6        31     30.0
    8     0        20     20.0
    9     1        20     20.0
    10    2        20     20.0
    11    3        21     20.0
    
  • Finally the adjustment of Res based on the 2 auxiliary columns: The zeros after the first A-value is exceeded.

Result for your example is as expected:

     A   COND  Res
0   28  False    0
1   30   True    0
2   15  False    1
3   25  False    2
4   24  False    3
5   13  False    4
6   31  False    0
7   19  False    0
8   20   True    0
9   11  False    1
10  19  False    2
11  21  False    0
Related