#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: Я обновил свой ответ. Вы можете проверить это сейчас?