Как подсчитать количество записей в строке и сбросить их при изменении поля

#python #pandas

#python #pandas

Вопрос:

Я пытаюсь подсчитать количество электронных писем, которые каждый пользователь открывает подряд. У меня есть данные, отсортированные по адресу электронной почты и дате, и я могу подсчитать # открыто в строке, но я не могу понять, как заставить его сбросить значение 0 при появлении нового адреса электронной почты.

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

 in_a_row = []
count = 0

for row in merge['Opened?']:
    if row == 1:
        count  = 1
        in_a_row.append(count)
    elif row == 0:
        count = 0
        in_a_row.append(count)
merged['in_a_row'] = in_a_row
 

Вот как это выглядит в настоящее время

 Index   email_address   sent_date      sent_rank  Opened?   in_a_row
0   email_A@gmail.com   5/15/2018          1          1         1
1   email_A@gmail.com   5/23/2018          2          0         0
2   email_A@gmail.com   5/23/2018          3          1         1
3   email_B@gmail.com   5/26/2018          1          1         2
4   email_B@gmail.com   5/27/2018          2          1         3
5   email_B@gmail.com   8/2/2018           3          0         0
6   email_B@gmail.com   8/3/2018           4          1         1
7   email_B@gmail.com   12/12/2018         5          1         2
8   email_C@gmail.com   12/12/2018         1          1         3
9   email_C@gmail.com   2/6/2019           2          0         0
10  email_C@gmail.com   2/12/2019          3          1         1
 

Вот как это должно выглядеть

 Index   email_address   sent_date      sent_rank  Opened?   in_a_row
0   email_A@gmail.com   5/15/2018          1          1         1
1   email_A@gmail.com   5/23/2018          2          0         0
2   email_A@gmail.com   5/23/2018          3          1         1
3   email_B@gmail.com   5/26/2018          1          1         1
4   email_B@gmail.com   5/27/2018          2          1         2
5   email_B@gmail.com   8/2/2018           3          0         0
6   email_B@gmail.com   8/3/2018           4          1         1
7   email_B@gmail.com   12/12/2018         5          1         2
8   email_C@gmail.com   12/12/2018         1          1         1
9   email_C@gmail.com   2/6/2019           2          0         0
10  email_C@gmail.com   2/12/2019          3          1         1
 

Комментарии:

1. Я не понимаю логику первого изменения с 1 на 0 in_a_row . Разве это не новый адрес?

2. При Opened? переходе от 1 к 0 одновременно email_address счетчик также сбрасывается?

3. Другой вопрос, почему все адреса электронной почты начинают подсчет с 0 , но первый адрес электронной почты начинается с 1 ?

4. Похоже, в таблицах были некоторые опечатки, извините за это, их следует исправить сейчас. При открытии? = 0, это означает, что электронное письмо было закрыто при открытии? = 1 это означает, что оно было открыто. Счетчик всегда должен сбрасываться на 0, когда электронное письмо не открывается, но он также должен сбрасываться на 0, когда появляется новый адрес электронной почты.

5. email_address всегда ли они группируются таким образом? т.Е. Можно ли увидеть email_A@gmail.com после email_C@gmail.com в строке 11 или 12?

Ответ №1:

Попробуйте это groupby.transform с помощью лямбда-выражения с использованием .ne ( != ), .shift , .cumsum и .add :

 g = df.groupby('email_address')
df['in_a_row'] = g['Opened?'].transform(lambda x: x * (x.groupby((x.ne(x.shift())).cumsum()).cumcount().add(x)))
 

Примечание: я думаю, что в вашем желаемом выводе все еще могут быть некоторые опечатки. например, idx 8 и 9 входные и выходные данные имеют разные значения для Opened?


[вывод]

     Index      email_address   sent_date  sent_rank  Opened?  in_a_row
0       0  email_A@gmail.com   5/15/2018          1        1         1
1       1  email_A@gmail.com   5/23/2018          2        0         0
2       2  email_A@gmail.com   5/23/2018          3        1         1
3       3  email_B@gmail.com   5/26/2018          1        1         1
4       4  email_B@gmail.com   5/27/2018          2        1         2
5       5  email_B@gmail.com    8/2/2018          3        0         0
6       6  email_B@gmail.com    8/3/2018          4        1         1
7       7  email_B@gmail.com  12/12/2018          5        1         2
8       8  email_C@gmail.com  12/12/2018          1        1         1
9       9  email_C@gmail.com    2/6/2019          2        0         0
10     10  email_C@gmail.com   2/12/2019          3        1         1
 

Комментарии:

1. Это действительно близко. Это работает для выборочных данных, но когда я применил его к большему набору данных, похоже, что есть исключения, которые не учитывались в данных выборки. Я обновил индекс 5, поэтому есть пример, когда он не работает. Теперь это открылось? при индексе 5 равно 0, in_a_row при индексе 6 должно быть 0, но вместо этого 2. Кроме того, вы были правы насчет опечаток, спасибо, что указали на них.

2. Спасибо, что указали на это @Tim344. посмотрим на это

3. @Tim344 обновил мой ответ, если вы хотите повторить это снова?