Слияние панд 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
Различные имена для ключевых столбцов
Если ключевые столбцы названы по-другому - например, lefthas keyLeftи righthas 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 merges)
Настроить
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.concatDataFrames присоединяется к 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поскольку он может обрабатывать неуникальные ключи (обратите внимание, что joinDataFrames присоединяется к их индексу; он вызывает внутреннее соединение 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=0or 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)
 
                Если вы хотите визуализировать, он работает так
 
                ( Источник )