Flag only first row where condition is met in a DataFrame
Use Series.shift
chained with &
for bitwise AND
:
df['hit_first'] = df['is_hit'].ne(df['is_hit'].shift()) & df['is_hit']
print (df)
vals is_hit hit_first
dates
2019-03-27 0.000000e+00 False False
2019-03-28 3.090170e-01 False False
2019-03-29 5.877853e-01 False False
2019-03-30 8.090170e-01 False False
2019-03-31 9.510565e-01 True True
2019-04-01 1.000000e+00 True False
2019-04-02 9.510565e-01 True False
2019-04-03 8.090170e-01 False False
2019-04-04 5.877853e-01 False False
2019-04-05 3.090170e-01 False False
2019-04-06 1.224647e-16 False False
2019-04-07 -3.090170e-01 False False
2019-04-08 -5.877853e-01 False False
2019-04-09 -8.090170e-01 False False
2019-04-10 -9.510565e-01 True True
2019-04-11 -1.000000e+00 True False
2019-04-12 -9.510565e-01 True False
2019-04-13 -8.090170e-01 False False
2019-04-14 -5.877853e-01 False False
2019-04-15 -3.090170e-01 False False
I also, think you can do it this way:
df['is_hit'].astype(int).diff() == 1
Output:
dates
2019-03-27 False
2019-03-28 False
2019-03-29 False
2019-03-30 False
2019-03-31 True
2019-04-01 False
2019-04-02 False
2019-04-03 False
2019-04-04 False
2019-04-05 False
2019-04-06 False
2019-04-07 False
2019-04-08 False
2019-04-09 False
2019-04-10 True
2019-04-11 False
2019-04-12 False
2019-04-13 False
2019-04-14 False
2019-04-15 False
Name: is_hit, dtype: bool
Timings:
%timeit df['is_hit'] & (~df['is_hit']).shift(1)
1.13 ms ± 5.63 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit df['is_hit'].ne(df['is_hit'].shift()) & df['is_hit']
908 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit df['is_hit'].astype(int).diff() == 1
689 µs ± 8.24 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
My suggestion:
df['hit_first'] = df['is_hit'] & (~df['is_hit']).shift(1)