Объединение многоиндексных данных с одноиндексными кадрами данных в pandas
У меня есть два кадра данных. df1 мультииндексирован:
value
first second
a x 0.471780
y 0.774908
z 0.563634
b x -0.353756
y 0.368062
z -1.721840
и df2:
value
first
a 10
b 20
Как я могу объединить два фрейма данных только с одним из мультииндексов, в этом случае "первым" индексом? Желаемый результат:
value1 value2
first second
a x 0.471780 10
y 0.774908 10
z 0.563634 10
b x -0.353756 20
y 0.368062 20
z -1.721840 20
Ответы
Ответ 1
Вы можете использовать get_level_values
:
firsts = df1.index.get_level_values('first')
df1['value2'] = df2.ix[firsts].values
Примечание: вы почти делаете join
здесь (кроме df1 является MultiIndex)... так что может быть более аккуратный способ чтобы описать это...
.
В примере (похоже на то, что у вас есть):
df1 = pd.DataFrame([['a', 'x', 0.123], ['a','x', 0.234],
['a', 'y', 0.451], ['b', 'x', 0.453]],
columns=['first', 'second', 'value1']
).set_index(['first', 'second'])
df2 = pd.DataFrame([['a', 10],['b', 20]],
columns=['first', 'value']).set_index(['first'])
firsts = df1.index.get_level_values('first')
df1['value2'] = df2.ix[firsts].values
In [5]: df1
Out[5]:
value1 value2
first second
a x 0.123 10
x 0.234 10
y 0.451 10
b x 0.453 20
Ответ 2
В соответствии с документацией, начиная с pandas 0.14, вы можете просто присоединиться к единичным и мультииндексным фреймам данных. Он будет соответствовать общему имени индекса. Аргумент how
работает, как и ожидалось, с помощью 'inner'
и 'outer'
, хотя интересно, что оно выглядит обратным для 'left'
и 'right'
(может это ошибка?).
df1 = pd.DataFrame([['a', 'x', 0.471780], ['a','y', 0.774908], ['a', 'z', 0.563634],
['b', 'x', -0.353756], ['b', 'y', 0.368062], ['b', 'z', -1.721840],
['c', 'x', 1], ['c', 'y', 2], ['c', 'z', 3],
],
columns=['first', 'second', 'value1']
).set_index(['first', 'second'])
df2 = pd.DataFrame([['a', 10], ['b', 20]],
columns=['first', 'value2']).set_index(['first'])
print(df1.join(df2, how='inner'))
value1 value2
first second
a x 0.471780 10
y 0.774908 10
z 0.563634 10
b x -0.353756 20
y 0.368062 20
z -1.721840 20
Ответ 3
Поскольку синтаксис .ix
является мощным ярлыком для переиндексации, но в этом случае вы фактически не выполняете переиндексацию строк/столбцов, это может быть сделано немного более элегантно (для моих скромных вкусовых рецепторов) с использованием только переиндексации:
Подготовка от хайдена:
df1 = pd.DataFrame([['a', 'x', 0.123], ['a','x', 0.234],
['a', 'y', 0.451], ['b', 'x', 0.453]],
columns=['first', 'second', 'value1']
).set_index(['first', 'second'])
df2 = pd.DataFrame([['a', 10],['b', 20]],
columns=['first', 'value']).set_index(['first'])
Тогда это выглядит так в iPython:
In [4]: df1
Out[4]:
value1
first second
a x 0.123
x 0.234
y 0.451
b x 0.453
In [5]: df2
Out[5]:
value
first
a 10
b 20
In [7]: df2.reindex(df1.index, level=0)
Out[7]:
value
first second
a x 10
x 10
y 10
b x 20
In [8]: df1['value2'] = df2.reindex(df1.index, level=0)
In [9]: df1
Out[9]:
value1 value2
first second
a x 0.123 10
x 0.234 10
y 0.451 10
b x 0.453 20
Мнемотехника, для какого уровня вы должны использовать метод reindex:
Он указывает на уровень, который вы уже охватили в более крупном индексе.
Итак, в этом случае df2 уже имел уровень 0, покрытый df1.index.