Цель этого поста - дать читателям представление о слиянии SQL с пандами, о том, как его использовать и когда его не использовать.
В частности, через этот пост будет проходить:
Что этосообщение не будет проходить:
- Обсуждения и время, связанные с производительностью (на данный момент).Наиболее примечательные упоминания о лучших альтернативах, где это уместно.
- Обработка суффиксов, удаление лишних столбцов, переименование выходных данных и другие конкретные случаи использования.Есть другие (читай: лучше) посты, которые имеют дело с этим, так что разберитесь!
Примечание
Большинство примеров по умолчанию используют операции 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](https://i.stack.imgur.com/YvuOa.png)
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](https://i.stack.imgur.com/BECid.png)
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](https://i.stack.imgur.com/8w1US.png)
...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](https://i.stack.imgur.com/euLoe.png)
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](https://i.stack.imgur.com/5qDIy.png)
Другие СОЕДИНЕНИЯ - ЛЕВЫЙ, ПРАВИЛЬНЫЙ, И ПОЛНЫЙ - исключая / ANTIСОЕДИНЕНИЯ
Если вам нужно СОЕДИНЕНИЯ ВЛЕВО * и СОКРАЩЕНИЯ ВПРАВО * в два этапа.
Для СОЕДИНЕНИЯ ВЛЕВО,представлен как
![image](https://i.stack.imgur.com/bXWIV.png)
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](https://i.stack.imgur.com/Z0br2.png)
(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](https://i.stack.imgur.com/PWMYd.png)
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
Этот раздел охватывает только самые основы и предназначен только для разжигания аппетита.Дополнительные примеры и примеры см. В документации по 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