Я создал df1 следующим образом:
df1 = pd.DataFrame(data=[
[ 1, 'Manchester', 'NH', 3108 ],
[ 1, 'Bedford', 'NH', 3188 ],
[ 6, 'Boston', 'MA', 23718 ],
[ 1, 'Austin', 'TX', 20034 ]],
columns=['ID', 'City', 'State', 'Zip'])
df1.Zip = df1.Zip.astype(str).str.zfill(5)
Обратите внимание, что я изменил источник Zip s (как я вижу, они "простые"
целые числа) в строку , потому что вы хотите иметь начальные нули.
Для создания df2 я использовал:
df2 = pd.DataFrame(data=[[ 1, 'Best Cities', 'xxx' ], [ 6, 'Worst Cities', 'yyy' ]],
columns=['ID', 'Title', 'Description'])
В качестве подготовительного шага давайте определим функцию, которая будет использоваться
агрегировать столбцы из df1 :
def fn(src):
lst = [ f'{idx}) {val}' for idx, val in enumerate(src, start=1) ]
return ', '.join(lst)
Первым шагом этой функции является понимание списка , где
перечисление итерации по src (содержимое текущего столбца
в текущей группе) и заменяет:
- idx - текущий индекс элемента, но начиная с 1,
- val - сам текущий элемент.
Выполняется форматирование элементов результата f-string .
Результатом является список, например, названия городов с номерами перед ними.
return оператор объединяет этот список в строку, вставляя ","
между ними.
Так, например для группы для столбцов ID == 1 и City исходные значения:
[ 'Manchester', 'Bedford', 'Austin' ]
и результат:
1) Manchester, 2) Bedford, 3)Austin
.
А фактическая обработка может быть выполнена с помощью одиночной инструкции:
pd.merge(df2, df1.groupby('ID').agg(fn), how='left',
left_on='ID', right_index=True).fillna('')
Как видите:
- Я изменил порядок объединенных фреймов данных. Таким образом, результат
содержит первые столбцы из df2 , затем из df1 .
- Город , Штат и Zip столбцы с df1 являются первыми
сгруппированы по ID и агрегированы с использованием функции fn .
- Затем они объединяются с df2 .
- Я добавил fillna ('') , чтобы заменить NaN значения пустой строкой,
что может произойти, если ID s присутствует только в df2 .