Заполнение колонки в pandas минимальным значением после groupby
Путанный заголовок получился, но смысл проблемы вот в чем. Есть табличка, которая выглядит таким образом:
q = pd.DataFrame({'first':[1, 2, 3, 2], 'days':['2019-10-19', '2019-10-20','2019-10-21', '2019-10-21']})
Нужно получить вот такую табличку:
q1 = pd.DataFrame({'first':[1, 2, 3, 2], 'days':['2019-10-19', '2019-10-20','2019-10-21', '2019-10-21'],
'days_min':['2019-10-19', '2019-10-20', '2019-10-19', '2019-10-20']})
То есть сгруппировать по первому столбцу, понять какая дата во втором столбце минимальна и именно ей заполнить третий столбец (сгруппированный по первому).
Я делаю вот так:
q['days_min'] = q.groupby('first').days.min()
Но все заполняется NAN-ами... не понимаю почему так :( Помогите, пожалуйста :(
Ответы (2 шт):
Если бы вы посмотрели результат группировки, то увидели бы, что там получается 3 значения. Ведь произошла группировка по колонке first, в которой 3 уникальных значения. Просто так нельзя эти 3 значения взять и записать в 4 ячейки таблицы (в одной из ячеек обязательно получится NA, да и не факт, что эти значения попадут в правильные строки). Нужно делать аналог SQL JOIN, чтобы значения попали во все строки таблицы с соответствующим значением first:
q1 = q.merge(q.groupby('first').min(),
on='first',
suffixes=('', '_min'))
q1
Вывод:
first days days_min
0 1 2019-10-19 2019-10-19
1 2 2019-10-20 2019-10-20
2 2 2019-10-21 2019-10-20
3 3 2019-10-21 2019-10-21
Сортировка строк получилась другая, потому что индекс перестроился, но данные получились именно какие вам нужны.
Если хотите сохранить порядок следования строк как в исходной таблице, то нужно делать аналог SQL LEFT JOIN, добавив параметр how='left':
q1 = q.merge(q.groupby('first').min(),
on='first',
how='left',
suffixes=('', '_min'))
Результат:
first days days_min
0 1 2019-10-19 2019-10-19
1 2 2019-10-20 2019-10-20
2 3 2019-10-21 2019-10-21
3 2 2019-10-21 2019-10-20
Спасибо за предложенный способ. Я на самом деле сделал немного иначе. Я сделал словарь, в котором каждому first сопоставил days.min(), а потом просто прошелся map:
fill_dict = q.groupby('first').days.min().to_dict()
q['days_min'] = q.first.map(fill_dict)
Сработало.