#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 — Не так просто, добавлены решения.