Заполнение колонки в 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 шт):

Автор решения: CrazyElf

Если бы вы посмотрели результат группировки, то увидели бы, что там получается 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
→ Ссылка
Автор решения: Alexey

Спасибо за предложенный способ. Я на самом деле сделал немного иначе. Я сделал словарь, в котором каждому first сопоставил days.min(), а потом просто прошелся map:

fill_dict = q.groupby('first').days.min().to_dict()
q['days_min'] = q.first.map(fill_dict)

Сработало.

→ Ссылка