Сравнение первой и последней строки groupby и создание нового значения

#python #pandas #group-by #pandas-groupby

Вопрос:

У меня есть фрейм данных с несколькими значениями, и я хотел бы сгруппироваться в столбце «электронная почта», получить первую строку и последнюю строку и сравнить, чтобы увидеть, изменилось ли состояние столбца категории. Например, если категория от MGR до MGR, то никаких изменений нет. Если категория меняется с EMP на MGR, то это отражает изменение статуса.

 date                 email               category
13-04-2018            johnson@abc.com     MGR
13-04-2018            linsay@abc.com      EMP
18-04-2018            kelphil@abc.com     EMP
20-04-2018            rsling@abc.com      MGR
11-01-2019            johnson@abc.com     MGR
15-10-2019            johnson@abc.com     MGR
16-11-2019            kelphil@abc.com     MGR
31-01-2020            sanson@abc.com      EMP
02-05-2020            rsling@abc.com      MGR
05-08-2020            rsling@abc.com      MGR
14-02-2021            sanson@abc.com      MGR
15-02-2021            linsay@abc.com      MGR

 

Хотелось бы получить следующие результаты

 date                 email               category    status
13-04-2018            johnson@abc.com     MGR        no change
15-10-2019            johnson@abc.com     MGR        no change
13-04-2018            linsay@abc.com      EMP        change
15-02-2021            linsay@abc.com      MGR        change
18-04-2018            kelphil@abc.com     EMP        change 
16-11-2019            kelphil@abc.com     MGR        change 
20-04-2018            rsling@abc.com      MGR        no change
05-08-2020            rsling@abc.com      MGR        no change
31-01-2020            sanson@abc.com      EMP        change 
14-02-2021            sanson@abc.com      MGR        change
 

Я попробовал следующий код, но, похоже, он извлекает только первую и последнюю строки на основе groupby. Есть ли какой — то метод для сравнения значений между первой и последней строкой?

 #get the first and last row of the groupby
df2 = df.groupby('email', as_index=False).nth([0,-1])
 

ценю любую форму помощи, спасибо.

Ответ №1:

Не уверен, что это достаточно эффективно, но работает хорошо.

 def check_status(group):
    selected = [False] * len(group)
    selected[0] = selected[-1] = True
    new_group = group[selected]
    new_group['status'] = 'change' if new_group.category.is_unique else 'no change'
    return new_group

print(df.groupby('email').apply(check_status).reset_index(drop=True))
 

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

1. кажется, это работает! Вы не могли бы объяснить, что делает selected = [False] * len(группа)?

2. Ну, это означает, что selected это список, в котором есть каждый элемент False и его длина равна len(group) . Я использую его, чтобы выбрать первого и последнего в группе. Я полагаю, что у панд есть какой-то способ сделать это более элегантно, но я не смог его найти. @wjie08

Ответ №2:

пробовать:

Это проверит, имеют ли элементы groupby одинаковые(одинаковые значения или нет), если есть какие-либо изменения, он установит флаг.

 fl = lambda s: s.iloc[[0,-1]]
res = df.groupby('email')['category'].apply(lambda x: (fl(x).shift(1).ne(fl(x)) amp; (fl(x).nunique()>1)))
res.index = res.index.droplevel()
df['status'] = res
df.dropna(inplace=True)
df['status'] = np.where(df.status,  'Change', 'No Change')
 

df.значения сортировки(по=’email’):

Дата Адрес электронной почты Категория Статус
0 13-04-2018 johnson@abc.com МГР Никаких Изменений
5 15-10-2019 johnson@abc.com МГР Никаких Изменений
2 18-04-2018 kelphil@abc.com EMP Изменить
6 16-11-2019 kelphil@abc.com МГР Изменить
1 13-04-2018 linsay@abc.com EMP Изменить
11 15-02-2021 linsay@abc.com МГР Изменить
3 20-04-2018 rsling@abc.com МГР Никаких Изменений
9 05-08-2020 rsling@abc.com МГР Никаких Изменений
7 31-01-2020 sanson@abc.com EMP Изменить
10 14-02-2021 sanson@abc.com МГР Изменить

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

1. это работает, но возможно ли, чтобы первая строка отражала статус, соответствующий последней строке? Значение для kelphil@abc.com, у нас есть статус = «изменено» при индексе = 2.

2. @wjie08: Я обновил свой ответ. Вы можете проверить это сейчас?