Панды Слияния 101 - PullRequest
       29

Панды Слияния 101

0 голосов
/ 06 декабря 2018
  • Как выполнить соединение (LEFT | RIGHT | FULL) (INNER | OUTER) с пандами?
  • Как добавить NaN для пропущенных строкпосле слияния?
  • Как избавиться от NaNs после слияния?
  • Можно ли слить по индексу?
  • Перекрестное соединение с пандами?
  • Как объединить несколько фреймов данных?
  • merge?join?concat?update?Кто?Какие?Почему?!

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

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

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

Ответы [ 2 ]

0 голосов
/ 26 апреля 2019

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

on pd.concat([df0, df1])

0 голосов
/ 06 декабря 2018

Цель этого поста - дать читателям представление о слиянии SQL с пандами, о том, как его использовать и когда его не использовать.

В частности, через этот пост будет проходить:

  • Основы - типы объединений (ВЛЕВО, ВПРАВО, ВНЕШНИЙ, ВНУТРЕННИЙ)

    • объединение с разными именами столбцов
    • избегание дублирования столбца ключа слиянияв выводе
  • Слияние с индексом при различных условиях
    • эффективное использование вашего именованного индекса
    • ключ слияния в качестве индекса одного и столбца другого
  • Многостороннее объединение столбцов и индексов (уникальных и неуникальных)
  • Известные альтернативы merge и join

Что этосообщение не будет проходить:

  • Обсуждения и время, связанные с производительностью (на данный момент).Наиболее примечательные упоминания о лучших альтернативах, где это уместно.
  • Обработка суффиксов, удаление лишних столбцов, переименование выходных данных и другие конкретные случаи использования.Есть другие (читай: лучше) посты, которые имеют дело с этим, так что разберитесь!

Примечание
Большинство примеров по умолчанию используют операции INNER JOIN при демонстрацииразличные функции, если не указано иное.

Кроме того, все кадры данных здесь можно копировать и реплицировать, чтобы вы могли поиграть с ними.Также см. этот пост о том, как читать фреймы данных из буфера обмена.

Наконец, все визуальное представление операций JOIN было нарисовано от руки с помощью Google Drawings.Вдохновение от здесь .

Достаточно Talk, просто покажите мне, как использовать 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

Ради простоты ключевой столбец имеет то же имя (пока).

INNER JOIN представлен

image

Note
This, along with the forthcoming figures all follow this convention:

  • blue indicates rows that are present in the merge result
  • red indicates rows that are excluded from the result (i.e., removed)
  • green indicates missing values that are replaced with NaNs in the result

To perform an INNER JOIN, call pd.merge с указанием левого DataFrame, правого DataFrame и ключа соединения.

pd.merge(left, right, on='key')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

Возвращает только строки из left и right, которые имеют общий ключ (в этом примере "B" и "D).

В более поздних версияхПанды (v0.21 или около того), merge теперь является функцией первого порядка, поэтому вы можете вызвать DataFrame.merge.

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

A LEFT OUTER JOIN , или LEFT JOIN представлен как

image

This can be performed by specifying 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

Carefully note the placement of NaNs here. If you specify how='left', then only keys from left are used, and missing data from right is replaced by NaN.

And similarly, for a RIGHT OUTER JOIN, or RIGHT JOIN which is...

image

...specify 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

Here, keys from right are used, and missing data from left is replaced by NaN.

Finally, for the FULL OUTER JOIN, given by

image

specify 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

This uses the keys from both frames, and NaNs are inserted for missing rows in both.

The documentation summarises these various merges nicely:

enter image description here

Другие СОЕДИНЕНИЯ - ЛЕВЫЙ, ПРАВИЛЬНЫЙ, И ПОЛНЫЙ - исключая / ANTIСОЕДИНЕНИЯ

Если вам нужно СОЕДИНЕНИЯ ВЛЕВО * и СОКРАЩЕНИЯ ВПРАВО * в два этапа.

Для СОЕДИНЕНИЯ ВЛЕВО,представлен как

image

Start by performing a LEFT OUTER JOIN and then filtering (excluding!) rows coming from left only,

(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

Where,

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

And similarly, for a RIGHT-Excluding JOIN,

image

(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

Lastly, if you are required to do a merge that only retains keys from the left or right, but not both (IOW, performing an ANTI-JOIN),

image

You can do this in similar fashion—

(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

Different names for key columns

If the key columns are named differently—for example, left has keyLeft, and right has keyRight instead of key—then you will have to specify left_on and right_on as arguments instead of 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

Avoiding duplicate key column in output

When merging on keyLeft from left and keyRight from right, if you only want either of the keyLeft or keyRight (but not both) in the output, you can start by setting the index as a preliminary step.

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

Contrast this with the output of the command just before (thst is, the output of left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), you'll notice keyLeft is missing. You can figure out what column to keep based on which frame's index is set as the key. This may matter when, say, performing some OUTER JOIN operation.

Merging only a single column from one of the DataFrames

For example, consider

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

If you are required to merge only "new_val" (without any of the other columns), you can usually just subset columns before merging:

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

If you're doing a LEFT OUTER JOIN, a more performant solution would involve 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

As mentioned, this is similar to, but faster than

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

Merging on multiple columns

To join on more than one column, specify a list for on (or left_on and right_on, as appropriate).

left.merge(right, on=['key1', 'key2'] ...)

Or, in the event the names are different,

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

Other useful merge* operations and functions

  • Merging a DataFrame with Series on index: See этот ответ .
  • Кроме merge, DataFrame.update и DataFrame.combine_firstтакже используются в некоторых случаях для обновления одного DataFrame другим.

  • pd.merge_ordered - полезная функция для упорядоченных соединений.

  • pd.merge_asof (читай: merge_asOf) полезно для приблизительно joins.

Этот раздел охватывает только самые основы и предназначен только для разжигания аппетита.Дополнительные примеры и примеры см. В документации по merge, join и concat, а также по ссылкам на спецификации функций.


На основе индекса * -JOIN (+ столбец индекса merge с)

Настройка

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 также могут указать имя уровня для 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 могла бы привести к ошибкеout:

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

Для получения дополнительной информации см. thisканоническое сообщение в pd.concat от @ piRSquared .


Обобщение: merge использование нескольких фреймов данных

Часто возникает ситуация, когда несколько фреймов данных объединяются вместе.На самом деле, это можно сделать с помощью цепочки вызовов merge:

df1.merge(df2, ...).merge(df3, ...)

Однако это быстро выходит из-под контроля для многих 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 к индексу .

# 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' для FULL OUTER JOIN.Обратите внимание, что вы не можете указать соединения 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...