Объединение двух фреймов данных pandas с многоиндексированными столбцами

#pandas #join #multi-index

#pandas #Присоединиться #многоиндексный

Вопрос:

Я хочу объединить два фрейма данных pandas, в одном из которых есть многоиндексированные столбцы.

Вот как я создаю первый фрейм данных.

 data_large = pd.DataFrame({"name":["a", "b", "c"], "sell":[10, 60, 50], "buy":[20, 30, 40]})
data_mini = pd.DataFrame({"name":["b", "c", "d"], "sell":[60, 20, 10], "buy":[30, 50, 40]})
data_topix = pd.DataFrame({"name":["a", "b", "c"], "sell":[10, 80, 0], "buy":[70, 30, 40]})

df_out = pd.concat([dfi.set_index('name') for dfi in [data_large, data_mini, data_topix]], 
                   keys=['Large', 'Mini', 'Topix'], axis=1)
           .rename_axis(mapper=['name'], axis=0).rename_axis(mapper=['product','buy_sell'], axis=1)
df_out
  

введите описание изображения здесь

И это второй фрейм данных.

 group = pd.DataFrame({"name":["a", "b", "c", "d"], "group":[1, 1, 2, 2]})
group
  

введите описание изображения здесь

Как я могу соединить второй фрейм с первым в столбце name , сохранив многоиндексированные столбцы?

Это не сработало, и мультииндекс стал плоским.

 df_final = df_out.merge(group, on=['name'], how='left')
  

Будем признательны за любую помощь!

введите описание изображения здесь

Ответ №1:

Если необходимо MultiIndex после merge преобразовать столбец group в MultiIndex DataFrame , вот преобразованный столбец name в индекс для объединения по индексу, иначе оба столбца должны быть преобразованы в MultiIndex :

 group = group.set_index('name')
group.columns = pd.MultiIndex.from_product([group.columns, ['new']])

df_final = df_out.merge(group, on=['name'], how='left')
  

Или:

 df_final = df_out.merge(group, left_index=True, right_index=True, how='left')
  

 print (df_final)
product  Large        Mini       Topix       group
buy_sell  sell   buy  sell   buy  sell   buy   new
name                                              
a         10.0  20.0   NaN   NaN  10.0  70.0     1
b         60.0  30.0  60.0  30.0  80.0  30.0     1
c         50.0  40.0  20.0  50.0   0.0  40.0     2
d          NaN   NaN  10.0  40.0   NaN   NaN     2
  

Другим возможным способом, но с предупреждением, является преобразование значений в MultiIndex after merge :

 df_final = df_out.merge(group, on=['name'], how='left')
  

Предупреждение пользователя: объединение между разными уровнями может дать непреднамеренный результат (2 уровня слева, 1 справа)
предупреждения.warn(сообщение, предупреждение пользователя)


 L = [x if isinstance(x, tuple) else (x, 'new') for x in df_final.columns.tolist()]
df_final.columns = pd.MultiIndex.from_tuples(L)   
print (df_final)
  name Large        Mini       Topix       group
   new  sell   buy  sell   buy  sell   buy   new
0    a  10.0  20.0   NaN   NaN  10.0  70.0     1
1    b  60.0  30.0  60.0  30.0  80.0  30.0     1
2    c  50.0  40.0  20.0  50.0   0.0  40.0     2
3    d   NaN   NaN  10.0  40.0   NaN   NaN     2
  

РЕДАКТИРОВАТЬ: При необходимости group в MultiIndex :

 group = group.set_index(['name'])
group.columns = pd.MultiIndex.from_product([group.columns, ['new']])

df_final = (df_out.merge(group, on=['name'], how='left')
                  .set_index([('group','new')], append=True)
                  .rename_axis(['name','group']))
print (df_final)
product    Large        Mini       Topix      
buy_sell    sell   buy  sell   buy  sell   buy
name group                                    
a    1      10.0  20.0   NaN   NaN  10.0  70.0
b    1      60.0  30.0  60.0  30.0  80.0  30.0
c    2      50.0  40.0  20.0  50.0   0.0  40.0
d    2       NaN   NaN  10.0  40.0   NaN   NaN
  

Или:

 df_final = df_out.merge(group, on=['name'], how='left').set_index(['name','group'])
df_final.columns = pd.MultiIndex.from_tuples(df_final.columns)
print (df_final)
           Large        Mini       Topix      
            sell   buy  sell   buy  sell   buy
name group                                    
a    1      10.0  20.0   NaN   NaN  10.0  70.0
b    1      60.0  30.0  60.0  30.0  80.0  30.0
c    2      50.0  40.0  20.0  50.0   0.0  40.0
d    2       NaN   NaN  10.0  40.0   NaN   NaN
  

Комментарии:

1. Спасибо за ответ! Возможно ли включить group в индекс строки? Итак, после объединения я хочу иметь name и group оба в индексе строки. Ваше решение дает два уровня ( group и new ), и я полагаю, это потому, что левый фрейм данных имеет два уровня. Но я хочу избежать этого, new поэтому я думаю, что лучше включить group в индекс строки…

2. @MakotoMiyazaki — Не так просто, добавлены решения.