Об'єднання панд 101


362
  • Як виконати приєднання ( LEFT| RIGHT| FULL) ( INNER| OUTER) з пандами?
  • Як додати NaN для пропущених рядків після об'єднання?
  • Як я можу позбутися NaNs після злиття?
  • Чи можу я злитися на індекс?
  • Перехресне з'єднання з пандами?
  • Як з'єднати кілька DataFrames?
  • merge? join? concat? update? ВООЗ? Що? Чому ?!

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

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

Зауважте, що ця публікація не є заміною документації , тому прочитайте її також! Деякі приклади взяті звідти.

Відповіді:


517

Ця публікація має на меті ознайомити читачів з букварями щодо злиття SQL з пандами, як їх використовувати, а коли не використовувати.

Зокрема, ось що пройде цей пост:

  • Основи - типи приєднань (Вліво, Вправо, ВІД, ІННЕР)

    • злиття з різними назвами стовпців
    • уникаючи дублювання стовпця ключа злиття у виході
  • Злиття з індексом за різних умов
    • ефективно використовуючи названий індекс
    • ключ злиття як індекс одного та стовпця іншого
  • Багатопотокові злиття на стовпцях та індексах (унікальні та не унікальні)
  • Помітні альтернативи 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

Щоб виконати ВНУТРІШНЕ 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, DataFrame.updateі DataFrame.combine_firstтакож використовується в деяких випадках для поновлення одного DataFrame з іншого.

  • pd.merge_ordered є корисною функцією для замовлених приєднань.

  • pd.merge_asof(читати: merge_asOf) корисний для приблизних приєднань.

Цей розділ охоплює лише основи, і він розроблений лише для того, щоб розкрити ваш апетит. Для більшого кількості прикладів і випадків, см документації на 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

49

Додатковий візуальний погляд на pd.concat([df0, df1], kwargs). Зауважте, що значення kwarg axis=0або axis=1's не таке інтуїтивне, як df.mean()абоdf.apply(func)


на pd.concat ([df0, df1])


9
Це хороша схема. Чи можу я запитати, як ви його виробили?
cs95

6
вбудований в Google "doc" doc ==> малюнок ... ==> новий "(станом на 2019 - травень). Але, щоб бути зрозумілим: єдина причина, за якою я використовував google doc для цієї картини, - це те, що мої нотатки зберігаються в google doc, і мені хотілося б зображення, яке можна швидко змінити в самій google doc. Насправді зараз ви це згадали, інструмент малювання google doc досить акуратний.
eliu

Ого, це чудово. Походить із світу SQL, "вертикальне" об'єднання - це не об'єднання в моїй голові, оскільки структура таблиці завжди виправлена. Тепер навіть думаю, що панда повинна консолідуватись concatта mergeмає параметр напрямку horizontalабо vertical.
Ufos

2
@Ufos Це не саме так axis=1і axis=0є?
cs95

2
да, там уже в даний час mergeі concatі вісь і все. Однак, як показує @eliu, все це саме те саме поняття злиття з "лівим" і "правим" і "горизонтальним" або "вертикальним". Мені особисто доводиться заглянути в документацію кожного разу, коли мені потрібно запам’ятати, яка «вісь» 0і яка 1.
Ufos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.