Слияние панд 101

Dec 06 2018
  • Как выполнить ( INNER| ( LEFT| RIGHT| FULL) OUTER) JOINс пандами?
  • Как добавить NaN для недостающих строк после слияния?
  • Как мне избавиться от NaN после слияния?
  • Могу я слить по индексу?
  • Перекрестное соединение с пандами?
  • Как объединить несколько DataFrames?
  • merge? join? concat? update? ВОЗ? Какие? Зачем?!

... и больше. Я видел эти повторяющиеся вопросы о различных аспектах функции слияния панд. Большая часть информации о слиянии и различных вариантах его использования сегодня фрагментирована по десяткам плохо сформулированных, не поддающихся поиску сообщений. Цель здесь - сопоставить некоторые из наиболее важных моментов для потомков.

Этот QnA должен стать следующим выпуском в серии полезных руководств пользователя по распространенным идиомам pandas (см. Этот пост о повороте и этот пост о конкатенации , о которых я буду говорить позже).

Обратите внимание, что этот пост не предназначен для замены документации , так что прочтите и его! Некоторые примеры взяты оттуда.

Ответы

696 cs95 Dec 06 2018 at 13:41

Этот пост призван дать читателям основы для слияния с использованием 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
62 eliu Apr 26 2019 at 06:43

Дополнительный визуальный вид pd.concat([df0, df1], kwargs). Обратите внимание, что значение kwarg axis=0or axis=1не так интуитивно понятно, как df.mean()ordf.apply(func)


5 GonçaloPeres龚燿禄 Aug 10 2020 at 17:13

В этом ответе я рассмотрю практический пример 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)

Если вы хотите визуализировать, он работает так

( Источник )