Слияние панд 101
- Как выполнить (
INNER
| (LEFT
|RIGHT
|FULL
)OUTER
)JOIN
с пандами? - Как добавить NaN для недостающих строк после слияния?
- Как мне избавиться от NaN после слияния?
- Могу я слить по индексу?
- Перекрестное соединение с пандами?
- Как объединить несколько DataFrames?
merge
?join
?concat
?update
? ВОЗ? Какие? Зачем?!
... и больше. Я видел эти повторяющиеся вопросы о различных аспектах функции слияния панд. Большая часть информации о слиянии и различных вариантах его использования сегодня фрагментирована по десяткам плохо сформулированных, не поддающихся поиску сообщений. Цель здесь - сопоставить некоторые из наиболее важных моментов для потомков.
Этот QnA должен стать следующим выпуском в серии полезных руководств пользователя по распространенным идиомам pandas (см. Этот пост о повороте и этот пост о конкатенации , о которых я буду говорить позже).
Обратите внимание, что этот пост не предназначен для замены документации , так что прочтите и его! Некоторые примеры взяты оттуда.
Ответы
Этот пост призван дать читателям основы для слияния с использованием SQL с пандами, как его использовать, а когда не использовать.
В частности, вот что будет происходить в этом посте:
Основы - типы соединений (LEFT, RIGHT, OUTER, INNER)
- слияние с разными именами столбцов
- предотвращение дублирования ключевого столбца слияния в выводе
Слияние с индексом при разных условиях
- эффективно используя ваш именованный индекс
- ключ слияния как индекс одного и столбца другого
Многостороннее слияние столбцов и индексов (уникальных и неуникальных)
Известные альтернативы
merge
иjoin
Что этот пост не пройдет:
- Обсуждения и сроки, связанные с производительностью (пока). В основном примечательные упоминания лучших альтернатив, где это возможно.
- Обработка суффиксов, удаление лишних столбцов, переименование выходных данных и другие конкретные варианты использования. Есть другие (читай: лучше) сообщения, которые касаются этого, так что разберитесь!
Примечание. В
большинстве примеров по умолчанию используются операции INNER JOIN при демонстрации различных функций, если не указано иное.Кроме того, все DataFrames здесь можно копировать и реплицировать, так что вы можете играть с ними. Также посмотрите этот пост о том, как читать DataFrames из буфера обмена.
Наконец, все визуальное представление операций JOIN было нарисовано вручную с помощью Google Drawings. Вдохновение отсюда .
Хватит разговоров, просто покажи мне, как пользоваться merge
!
Настроить
np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})
left
key value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right
key value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
Для простоты ключевой столбец имеет то же имя (пока).
Внутреннее соединение представлено
Обратите внимание: все
это, а также следующие цифры следуют этому соглашению:
- синий указывает строки, которые присутствуют в результате слияния
- красный означает строки, которые исключены из результата (т. е. удалены)
- зеленый цвет указывает на отсутствующие значения, которые
NaN
в результате заменяются буквой s
Чтобы выполнить INNER JOIN, вызовите merge
левый DataFrame, указав правый DataFrame и ключ соединения (по крайней мере) в качестве аргументов.
left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
Это возвращает только строки из left
и right
которые имеют общий ключ (в этом примере «B» и «D»).
LEFT OUTER JOIN или LEFT JOIN представлена
Это можно сделать, указав how='left'
.
left.merge(right, on='key', how='left')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
Внимательно обратите внимание на размещение NaN здесь. Если вы укажете how='left'
, то используются только ключи из left
, а отсутствующие данные из right
заменяются на NaN.
И аналогично, для ПРАВОГО ВНЕШНЕГО СОЕДИНЕНИЯ или ПРАВОГО СОЕДИНЕНИЯ, которое ...
... укажите how='right'
:
left.merge(right, on='key', how='right')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
2 E NaN 0.950088
3 F NaN -0.151357
Здесь используются ключи from right
, а отсутствующие данные из left
заменяются NaN.
Наконец, для ПОЛНОГО ВНЕШНЕГО СОЕДИНЕНИЯ , заданного
указать how='outer'
.
left.merge(right, on='key', how='outer')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
4 E NaN 0.950088
5 F NaN -0.151357
При этом используются ключи из обоих кадров, и NaN вставляются для отсутствующих строк в обоих.
Документация хорошо резюмирует эти различные слияния:
Другие соединения - LEFT-Excluding, RIGHT-Excluding и FULL-Excluding / ANTI JOIN.
Если вам нужно LEFT-Excluding JOINs и RIGHT-Excluding JOINs в два шага.
Для LEFT-Excluding JOIN, представленного как
Начните с выполнения LEFT OUTER JOIN, а затем фильтрации (исключая!) Строк, поступающих left
только из ,
(left.merge(right, on='key', how='left', indicator=True)
.query('_merge == "left_only"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
Куда,
left.merge(right, on='key', how='left', indicator=True)
key value_x value_y _merge
0 A 1.764052 NaN left_only
1 B 0.400157 1.867558 both
2 C 0.978738 NaN left_only
3 D 2.240893 -0.977278 both
И аналогично, для RIGHT-Excluding JOIN,
(left.merge(right, on='key', how='right', indicator=True)
.query('_merge == "right_only"')
.drop('_merge', 1))
key value_x value_y
2 E NaN 0.950088
3 F NaN -0.151357
Наконец, если вам необходимо выполнить слияние, которое сохраняет только ключи слева или справа, но не оба сразу (IOW, выполнение ANTI-JOIN ),
Вы можете сделать это аналогичным образом -
(left.merge(right, on='key', how='outer', indicator=True)
.query('_merge != "both"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
4 E NaN 0.950088
5 F NaN -0.151357
Различные имена для ключевых столбцов
Если ключевые столбцы названы по-другому - например, left
has keyLeft
и right
has keyRight
вместо - key
тогда вам нужно будет указать left_on
и в right_on
качестве аргументов вместо on
:
left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)
left2
keyLeft value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right2
keyRight value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
keyLeft value_x keyRight value_y
0 B 0.400157 B 1.867558
1 D 2.240893 D -0.977278
Избегайте дублирования ключевого столбца в выводе
При объединении keyLeft
из left
и keyRight
из right
, если вы хотите, чтобы на выходе было только одно keyLeft
или keyRight
(но не оба), вы можете начать с установки индекса в качестве предварительного шага.
left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')
value_x keyRight value_y
0 0.400157 B 1.867558
1 2.240893 D -0.977278
Сравните это с выводом команды непосредственно перед (то есть выводом left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
), вы заметите, что keyLeft
он отсутствует. Вы можете определить, какой столбец оставить, исходя из индекса кадра, установленного в качестве ключа. Это может иметь значение, например, при выполнении некоторой операции OUTER JOIN.
Объединение только одного столбца из одного из DataFrames
Например, рассмотрим
right3 = right.assign(newcol=np.arange(len(right)))
right3
key value newcol
0 B 1.867558 0
1 D -0.977278 1
2 E 0.950088 2
3 F -0.151357 3
Если вам необходимо объединить только «new_val» (без каких-либо других столбцов), вы обычно можете просто подмножество столбцов перед объединением:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
Если вы выполняете LEFT OUTER JOIN, более производительное решение будет включать map
:
# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Как уже упоминалось, это похоже на, но быстрее, чем
left.merge(right3[['key', 'newcol']], on='key', how='left')
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Слияние нескольких столбцов
Чтобы присоединиться к нескольким столбцам, укажите список для on
(или left_on
и right_on
, если необходимо).
left.merge(right, on=['key1', 'key2'] ...)
Или, если имена разные,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
Другие полезные merge*
операции и функции
Объединение DataFrame с серией по индексу : см. Этот ответ .
Кроме того
merge
,DataFrame.update
иDataFrame.combine_first
также используются в некоторых случаях для обновления одного DataFrame другим.pd.merge_ordered
полезная функция для упорядоченных СОЕДИНЕНИЙ.pd.merge_asof
(читайте: merge_asOf) полезно для приблизительных объединений.
Этот раздел охватывает только самые основы и предназначен только для того, чтобы подогреть ваш аппетит. Для большего количества примеров и случаев, см документации на merge
, join
иconcat
так же , как и ссылки на функцию спецификацию.
На основе индекса * -JOIN (+ index-column merge
s)
Настроить
np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'
left
value
idxkey
A -0.602923
B -0.402655
C 0.302329
D -0.524349
right
value
idxkey
B 0.543843
D 0.013135
E -0.326498
F 1.385076
Обычно слияние по индексу выглядит так:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Поддержка имен индексов
Если ваш индекс назван, то пользователи v0.23 также могут указать имя уровня to on
(или left_on
и по right_on
мере необходимости).
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Слияние по индексу одного столбца (столбцов) другого
Можно (и довольно просто) использовать индекс одного и столбец другого для выполнения слияния. Например,
left.merge(right, left_on='key1', right_index=True)
Или наоборот ( right_on=...
и left_index=True
).
right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2
colkey value
0 B 0.543843
1 D 0.013135
2 E -0.326498
3 F 1.385076
left.merge(right2, left_index=True, right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
В этом особом случае указан индекс для left
, поэтому вы также можете использовать имя индекса left_on
, например:
left.merge(right2, left_on='idxkey', right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
DataFrame.join
Кроме них есть еще один емкий вариант. Вы можете использовать DataFrame.join
значения по умолчанию для объединений в индексе. DataFrame.join
по умолчанию делает LEFT OUTER JOIN, поэтому how='inner'
здесь это необходимо.
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Обратите внимание , что мне нужно было указать lsuffix
и rsuffix
аргументы , так как в join
противном случае ошибки будет из:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
Так как названия столбцов совпадают. Это не было бы проблемой, если бы они были названы по-другому.
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
Наконец, в качестве альтернативы объединениям на основе индекса вы можете использовать pd.concat
:
pd.concat([left, right], axis=1, sort=False, join='inner')
value value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Пропустите, join='inner'
если вам нужно ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (по умолчанию):
pd.concat([left, right], axis=1, sort=False)
value value
A -0.602923 NaN
B -0.402655 0.543843
C 0.302329 NaN
D -0.524349 0.013135
E NaN -0.326498
F NaN 1.385076
Для получения дополнительной информации см. Этот канонический пост на pd.concat
@piRSquared .
Обобщение: использование merge
нескольких фреймов данных
Часто возникает ситуация, когда необходимо объединить несколько DataFrames. Наивно, это можно сделать, объединив merge
вызовы:
df1.merge(df2, ...).merge(df3, ...)
Однако для многих DataFrame это быстро выходит из-под контроля. Кроме того, может потребоваться обобщение для неизвестного количества DataFrames.
Здесь я рассказываю pd.concat
о многосторонних соединениях по уникальным ключам и DataFrame.join
о многосторонних соединениях по неуникальным ключам. Во-первых, настройка.
# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C]
# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')
dfs2 = [A2, B2, C2]
Многостороннее слияние уникальных ключей (или индекса)
Если ваши ключи (здесь ключ может быть либо столбцом, либо индексом) уникальны, вы можете использовать pd.concat
. Обратите внимание, что pd.concat
DataFrames присоединяется к index .
# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')
valueA valueB valueC
key
D 2.240893 -0.977278 1.0
Пропустите join='inner'
ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ. Обратите внимание, что вы не можете указать соединения LEFT или RIGHT OUTER (если они вам нужны, используйте join
, как описано ниже).
Многостороннее слияние ключей с дубликатами
concat
работает быстро, но имеет свои недостатки. Он не может обрабатывать дубликаты.
A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})
pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)
В этой ситуации мы можем использовать, join
поскольку он может обрабатывать неуникальные ключи (обратите внимание, что join
DataFrames присоединяется к их индексу; он вызывает внутреннее соединение merge
и выполняет LEFT OUTER JOIN, если не указано иное).
# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
[df.set_index('key') for df in (B, C)], how='inner').reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')
valueA valueB valueC
key
D 1.454274 -0.977278 1.0
D 0.761038 -0.977278 1.0
Дополнительный визуальный вид pd.concat([df0, df1], kwargs)
. Обратите внимание, что значение kwarg axis=0
or axis=1
не так интуитивно понятно, как df.mean()
ordf.apply(func)
В этом ответе я рассмотрю практический пример pandas.concat
.
Учитывая следующее DataFrames
с теми же именами столбцов:
Preco2018 с размером (8784, 5)
Preco 2019 с размером (8760, 5)
У них такие же имена столбцов.
Вы можете комбинировать их pandas.concat
, просто
import pandas as pd
frames = [Preco2018, Preco2019]
df_merged = pd.concat(frames)
В результате получается DataFrame следующего размера (17544, 5)
Если вы хотите визуализировать, он работает так
( Источник )