Ця публікація має на меті ознайомити читачів з букварями щодо злиття 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 .
Узагальнення: merge
ing. Декілька 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