Ця публікація має на меті ознайомити читачів з букварями щодо злиття SQL з пандами, як їх використовувати, а коли не використовувати.
Зокрема, ось що пройде цей пост:
Що ця публікація не переживе:
- Дискусії та терміни, що стосуються результатів (поки що). Здебільшого помітні згадки про кращі альтернативи, де це можливо.
- Обробка суфіксів, видалення зайвих стовпців, перейменування результатів та інші конкретні випадки використання. Є й інші (читайте: краще) публікації, які займаються цим, тому розібрайтеся!
Примітка
Більшість прикладів за замовчуванням для операцій 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
Щоб виконати ВНУТРІШНЕ 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
Тут використовуються ключі від 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
Тут використовуються клавіші обох кадрів, а NaNs вставляються для відсутніх рядків в обох.
Документація добре узагальнює ці різні об'єднання:

Інші ПРИЄДНАЮТЬСЯ - ВИКЛЮЧАЮЩИЙ ЛІВО, ПРАВИЛЬНИЙ, НЕ ПРАВИЛЬНИЙ, А ПОЛІТИЧНИЙ / НЕ ПРИЄДНАЙТЕСЬ
Якщо вам потрібні СПІЛКИ, що виключають ЛІВО, та ПРИЄДНАЄТЬСЯ ПРИЄДНАЙТЕСЯ в два етапи
Для ПРИЄДНУВАННЯ ВЛЕВО, що не включається, представлена як

Почніть з виконання лівого зовнішнього приєднання, а потім фільтруючи (виключаючи!) Рядки, що надходять 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
І аналогічно, ПРИЄДНАЙТЕ ПРИЄДНАЙТЕСЬ,

(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, виконуючи АНТИ-ПРИЄДНУЙСЯ ),

Ви можете зробити це подібним чином -
(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має keyLeft, а rightмає 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
Якщо ви робите СПІЛЬНЕ ВИХІДНЕ ПРИЄДНАННЯ, більш ефективне рішення передбачає 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*операції та функції
Цей розділ охоплює лише основи, і він розроблений лише для того, щоб розкрити ваш апетит. Для більшого кількості прикладів і випадків, см документації на 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приєднується ліворуч зовні, за замовчуванням, тому 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 .
Узагальнення: mergeing. Декілька DataFrames
Часто виникає ситуація, коли декілька DataFrames повинні бути об'єднані разом. Наївно це можна зробити за допомогою ланцюга 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'ПОВНОГО ВІДПРИЄМСТВА. Зауважте, що ви не можете вказати приєднання Ліворуч або Право 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під кришкою і робить ЛІВНІЙ ВИХІД ПРИЄДНАННЯ, якщо не вказано інше).
# 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