Вопрос по объединению DataFrame

Есть dataframe

ID Name Price
Совпадение Название1 Цена1
21cd1231dw czxca21 1324512
Совпадение Название2 Цена2
Совпадение Название3 Цена3

Надо по нему пробежаться и если совпадает id добавляем дубль справа в столбцы с названием name_1 и price_1

если совпадений несколько то добавляем name_2 , name_55 и тд

пробовал поиграться с объединением dataframe merge:

df_merged = df.merge(df, on='ID')

Дубли не удаляет на выходе получается

ID Name Price NAme_x Price_x"
Совпадение Название1 цена 1 Название2 Цена2
Совпадение Название1 цена 1 Название 3 Цена3
3123asdas asdased2 12315125

Если использую

df_merged = df.join(df, rsuffix='_right') 

просто находит строку и справа делает ее дубль

Короче все варианты перепробовал и более или мене что работает это .merge и то дубли оставляет.

Объясните пожалуйста, что делаю не так?

Получается даже не так, просто он находит строку и копирует ее справа за исключением ID. А нужно чтобы все id объединились в одну строку.

На выходе я хочу получить

ID Name Price NAme_x Price_x" Name_y Price_y
Совпадение1 Название1 цена 1 Название2 Цена2 Название3 Цена3
Совпадение2 ыфввыф 15251423 фывфыв 12331
Совпадение3 asdased2 12315125

т.е 1 строка формируется из всех строк с значением id = Совпадение1, а справа пишем значения Name и Price тех строк где id совпало и тд


Ответы (1 шт):

Автор решения: D.Vinogradov

Можно так попробовать.

Допустим у нас есть такой df

>>> df
   id name  price
0   1    a    100
1   1    b    200
2   1    c    300
3   2    d    400
4   2    e    500
5   2    f    600
6   3    g    700
7   3    h    800
8   1    j    900

Тогда.

Вариант 1:

new_df = df.assign(k=df.groupby(['id']).cumcount()).set_index(['id', 'k']).unstack()

Переименуем столбцы

new_df.columns = [f'{x}_{y}' for x, y in new_df.columns]

Отсортируем, чтобы столбцы были в нужном вам порядке и сбросим индекс

new_df = new_df.reindex(sorted(new_df.columns, key=lambda x: x[-1]), axis=1).reset_index()

Получаем:

>>> new_df

   id name_0  price_0 name_1  price_1 name_2  price_2 name_3  price_3
0   1      a    100.0      b    200.0      c    300.0      j    900.0
1   2      d    400.0      e    500.0      f    600.0    NaN      NaN
2   3      g    700.0      h    800.0    NaN      NaN    NaN      NaN

Вариант 2 (Вроде проще):

Без группировке в данном случае все равно никуда, поэтому

df = df.groupby('id').agg(name=('name', lambda x: x.to_list()), price=('price', lambda x: x.to_list())).reset_index()

Далее создадим функцию, которая принимает на вход ваш датафрейм и название столбца и возвращает новый датафрейм.

def return_col(your_df, col: str):
    list_of = your_df[col].to_list()
    max_len_of = max([len(i) for i in list_of])
    df_of = pd.DataFrame(list_of, columns=[f'{col}_{i}' for i in range(max_len_of)]).fillna(np.nan)
    return df_of

пример:

>>> print(return_col(df, 'name'))
  name_0 name_1 name_2 name_3
0      a      b      c      j
1      d      e      f    NaN
2      g      h    NaN    NaN

с помощью данной функции создадим несколько новых df для начальных столбцов

name = return_col(df, 'name')
price = return_col(df, 'price')

соединим их и отсортируем

df_np = pd.concat([name, price], axis=1)
df_np = df_np[sorted(df_np, key=lambda x: x[-1])]

и добавим наш id

df_last = pd.concat([df['id'], df_np], axis=1)

получим

>>> df_last

   id name_0  price_0 name_1  price_1 name_2  price_2 name_3  price_3
0   1      a      100      b      200      c    300.0      j    900.0
1   2      d      400      e      500      f    600.0    NaN      NaN
2   3      g      700      h      800    NaN      NaN    NaN      NaN

p.s. На мой взгляд первый вариант надежнее

→ Ссылка