Найдите последовательные значения панд с некоторыми условиями

Я пытаюсь найти последовательные нулевые значения и застрял с этой проблемой на пару часов.

У меня есть DataFrame, например:

Day  |  ID  |  Values
-------------------
1    |  aa  |    0
1    |  aa  |    0
1    |  aa  |    0
1    |  aa  |    0
1    |  aa  |    2.5
1    |  aa  |    2.3
1    |  aa  |    0
1    |  aa  |    0
1    |  aa  |    0
2    |  aa  |    0
2    |  aa  |    0
2    |  aa  |    2.3
2    |  aa  |    0
1    |  bb  |    0
1    |  bb  |    0
1    |  bb  |    0
1    |  bb  |    0
1    |  bb  |    3.5

Я хочу найти последовательные значения нулей следующим образом:

Day  |  ID  |  Values   | consec_zeros
--------------------------------------
1    |  aa  |    0      |      0
1    |  aa  |    0      |      1
1    |  aa  |    0      |      2
1    |  aa  |    0      |      3
1    |  aa  |    2.5    |      4      # --> there were 4 of consecutive 0s 
1    |  aa  |    2.3    |      0      # 2.5 just destroy consecutive values
1    |  aa  |    0      |      0
1    |  aa  |    0      |      1
1    |  aa  |    0      |      2      
2    |  aa  |    0      |      0      # no 0s before this of Day 2
2    |  aa  |    0      |      1
2    |  aa  |    2.3    |      2
2    |  aa  |    0      |      0
1    |  bb  |    0      |      0     # --> no 0s before this in ID 'bb'
1    |  bb  |    0      |      1
1    |  bb  |    0      |      2
1    |  bb  |    0      |      3
1    |  bb  |    3.5    |      4

То, что я пытался сделать, было:

g = df['Values'].ne(df['Values'].shift(1)).cumsum()
counts = df.groupby(['ID','Day',g])['Values'].transform('size')
df['consec_zeros'] = np.where(df['Values'].eq(0), counts, 0)

Поскольку я новичок в этом, пожалуйста, помогите и укажите мне, что я сделал неправильно.

заранее спасибо

Возможный дубликат GroupBy Pandas считает последовательные нули

ascripter 13.06.2019 14:02

@ascripter Я уже просматривал этот поток, но вывод последовательных zeos не в формате приращения, как мой желаемый вывод.

benji 13.06.2019 14:05
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
179
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот основная проблема: добавить следующее значение счетчика по первым ненулевым значениям по GroupBy.cumcount, но также использовать его для обнуления, в моем решении было добавлено 1 к счетчику для различения первого значения в счетчике:

g = df['Values'].ne(df['Values'].shift(1)).cumsum()
counts = df.groupby(['ID','Day',g])['Values'].cumcount() + 1
df['consec_zeros'] = np.where(df['Values'].eq(0), counts, 0)

#replace 0 to `NaN`s
a = df['consec_zeros'].mask(df['consec_zeros'].eq(0))
#add 1 to forward filling missing values by limit 1 per groups
df['consec_zeros'] = (np.where(a.isna(), 
                               a.groupby([df['ID'],df['Day']]).ffill(limit=1) + 1, 
                               df['consec_zeros']) - 1)
df['consec_zeros'] = df['consec_zeros'].fillna(0).astype(int)
print (df)
    Day  ID  Values  consec_zeros
0     1  aa     0.0             0
1     1  aa     0.0             1
2     1  aa     0.0             2
3     1  aa     0.0             3
4     1  aa     2.5             4
5     1  aa     2.3             0
6     1  aa     0.0             0
7     1  aa     0.0             1
8     1  aa     0.0             2
9     2  aa     0.0             0
10    2  aa     0.0             1
11    2  aa     2.3             2
12    2  aa     0.0             0
13    1  bb     0.0             0
14    1  bb     0.0             1
15    1  bb     0.0             2
16    1  bb     0.0             3
17    1  bb     3.5             4

Спасибо с хорошим объяснением. Это действительно работает. Большое спасибо!

benji 13.06.2019 14:20

@benji - я думаю, что нашел ошибку, необходимо заполнить форму по группам, поэтому отредактировал ответ.

jezrael 13.06.2019 14:23

Другие вопросы по теме