Сообщить об ошибке.

Соединение pandas.DataFrame в стиле базы данных

Синтаксис:

# метод `DataFrame`, который считается
# левым объектом в соединении
new_df = DataFrame.merge(right, how='inner', on=None, left_on=None, 
                         right_on=None, left_index=False, right_index=False, 
                         sort=False, suffixes=('_x', '_y'), copy=None, 
                         indicator=False, validate=None)

# функция пространства имен pandas
# аргумент `left` - это левый `DataFrame`
import pandas as pd
new_df = pd.merge(left, right, how='inner', on=None, left_on=None, 
                  right_on=None, left_index=False, right_index=False, 
                  sort=False, suffixes=('_x', '_y'), copy=None, 
                  indicator=False, validate=None)

Параметры:

  • right - DataFrame или именованный Series для слияния. Именованный Series - это значит имеет не пустой атрибут Series.name.

  • how='inner' - тип слияния, которое необходимо выполнить.

    Принимает следующие строки:

    • left: использовать ключи только из левого DataFrame, аналогично левому внешнему соединению SQL. Сохраняет порядок ключей.
    • right: использовать ключи только из правого DataFrame, аналогично правому внешнему соединению SQL. Сохраняет порядок ключей.
    • outer: использовать объединение ключей из обоих DataFrame, аналогично полному внешнему соединению SQL. Сортирует ключи лексикографически.
    • inner: использовать пересечение ключей из обоих DataFrame, аналогично внутреннему соединению SQL. Сохраняет порядок левых ключей.
    • cross: создает декартово произведение из обоих DataFrame, сохраняет порядок левых ключей.

  • on=None - список имен индексов или уровней столбцов для объединения. Они должны присутствовать в обоих DataFrames. Если включено значение None и индексы не объединяются, то по умолчанию это пересечение столбцов в обоих DataFrames.

  • left_on=None - имена индексов или уровней столбцов для объединения в левом DataFrame. Также может быть массивом или списком массивов длиной с левый DataFrame. Эти массивы обрабатываются так, как если бы они были столбцами.

  • right_on=None - имена индексов или уровней столбцов для объединения в правом DataFrame. Также может быть массивом или списком массивов длиной с правый DataFrame. Эти массивы обрабатываются так, как если бы они были столбцами.

  • left_index=False - использовать индекс из левого DataFrame в качестве ключа(ей) соединения. Если это MultiIndex, то количество ключей в другом DataFrame (либо индекс, либо количество столбцов) должно соответствовать количеству уровней.

  • right_index=False - использовать индекс из правого DataFrame в качестве ключа(ей) соединения. Если это MultiIndex, то количество ключей в другом DataFrame (либо индекс, либо количество столбцов) должно соответствовать количеству уровней.

  • sort=False - лексикографическая сортировка ключей соединения в результирующем DataFrame. Если значение равно False, порядок ключей соединения зависит от типа соединения (аргумент how).

  • suffixes=('_x', '_y') - суффикс, добавляемый к перекрывающимся именным столбцам слева и справа соответственно. Значение None вместо строки указывает, что имя столбца слева или справа следует оставить как есть, без суффикса.

  • copy=None - если значение равно False, по возможности избегает копирования.

    Аргумент copy изменит поведение в pandas 3.0. Копирование при записи будет включено по умолчанию, а это означает, что все методы с аргументом copy будут использовать механизм отложенного копирования и игнорировать аргумент copy. Ключевой аргумент copy будет удален в будущей версии pandas. Можно уже сейчас получить будущее поведение и улучшения, включив копирование при записи pd.options.mode.copy_on_write = True

  • indicator=False - если значение True, то в выходной DataFrame добавляется столбец с именем _merge с информацией об источнике каждой строки. Столбцу можно дать другое имя, указав строку вместо True.

    Столбец будет иметь категориальный тип со значением:

    • left_only для наблюдений, ключ которых появляется только в левом DataFrame,
    • right_only для наблюдений, ключ которых появляется только в правом DataFrame,
    • both, если ключ слияния наблюдения находится в обоих DataFrame.

  • validate=None - если указано, то проверяет, имеет ли соединение указанный тип.

    Принимает следующие строки:

    • 'one_to_one' или '1:1': проверяет, уникальны ли ключи соединения как в левом, так и в правом наборах данных.
    • 'one_to_many' или '1:m': проверяет, уникальны ли ключи соединения в левом наборе данных.
    • 'many_to_one' или 'm:1': проверяет, уникальны ли ключи соединения в правом наборе данных.
    • 'many_to_many' или 'm:m': допускается, но не приводит к проверкам.

Возвращаемое значение:

  • DataFrame двух объединенных объектов.

Описание метода DataFrame.merge()

Метод DataFrame.merge() модуля pandas выполняет объединение DataFrame или именованные объекты Series (считаются левым объектом) с помощью соединения в стиле базы данных.

Именованный объект Series рассматривается как DataFrame с одним именованным столбцом.

Соединение выполняется по столбцам или индексам. При соединении, в которых участвуют столбцы - индексы DataFrame будут проигнорированы. В противном случае, при соединении индексов с индексами или индексов в столбце или столбцах, индекс будет передан дальше. При выполнении перекрестного слияния не допускаются никакие спецификации столбцов для слияния.

Функция pandas.merge() это функция в пространстве имен библиотеки pandas, она также доступна как метод экземпляра DataFrame merge() (представленный выше), при этом вызывающий DataFrame неявно считается левым объектом в соединении.

Предупреждение. Если оба ключевых столбца содержат строки, где ключ имеет значение NA, то эти строки будут сопоставлены друг с другом. Это отличается от обычного поведения соединения SQL и может привести к неожиданным результатам.

Опытные пользователи реляционных баз данных, таких как SQL, знакомы с терминологией, используемой для описания операций соединения между двумя структурами, подобными таблицам SQL (объектами DataFrame).

Есть несколько случаев, которые очень важно понять:

  • соединения one-to-one: например, при соединении двух объектов DataFrame по их индексам (которые должны содержать уникальные значения).
  • соединения many-to-one: например, при присоединении индекса (уникального) к одному или нескольким столбцам в другом DataFrame.
  • соединения many-to-many: соединение столбцов со столбцами.

Примечание. При объединении столбцов со столбцами (возможно, соединение many-to-many) любые индексы переданных объектов DataFrame будут отброшены.

В SQL (стандартной реляционной алгебре), если комбинация ключей встречается более одного раза в обеих таблицах, то результирующая таблица будет иметь декартово произведение связанных данных. Для понимания о чем речь, простой пример с одной уникальной комбинацией ключей:

>>> import pandas as pd

left = pd.DataFrame(
    {
        "key": ["K0", "K1", "K2", "K3"],
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
    }
)

right = pd.DataFrame(
    {
        "key": ["K0", "K1", "K2", "K3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

>>> pd.merge(left, right, on="key")
#   key   A   B   C   D
# 0  K0  A0  B0  C0  D0
# 1  K1  A1  B1  C1  D1
# 2  K2  A2  B2  C2  D2
# 3  K3  A3  B3  C3  D3

Более сложный пример с несколькими ключами соединения. Присутствуют только ключи, появляющиеся слева и справа (пересечение), т.к. соединение по умолчанию how='inner'.

left = pd.DataFrame(
    {
        "key1": ["K0", "K0", "K1", "K2"],
        "key2": ["K0", "K1", "K0", "K1"],
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
    }
)

right = pd.DataFrame(
    {
        "key1": ["K0", "K1", "K1", "K2"],
        "key2": ["K0", "K0", "K0", "K0"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

>>> pd.merge(left, right, on=["key1", "key2"])
#   key1 key2   A   B   C   D
# 0   K0   K0  A0  B0  C0  D0
# 1   K1   K0  A2  B2  C1  D1
# 2   K1   K0  A2  B2  C2  D2

Аргумент how

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

Метод объединенияАналог SQLОписание
leftLEFT OUTER JOINИспользует ключи только из левого DataFrame
rightRIGHT OUTER JOINИспользует ключи только из правого DataFrame
outerFULL OUTER JOINИспользует объединение ключей из обоих DataFrame
innerINNER JOINИспользует пересечение ключей из обоих DataFrame
crossCROSS JOINСоздает декартово произведение строк обоих DataFrame.
# how="left"
>>> pd.merge(left, right, how="left", on=["key1", "key2"])
#   key1 key2   A   B    C    D
# 0   K0   K0  A0  B0   C0   D0
# 1   K0   K1  A1  B1  NaN  NaN
# 2   K1   K0  A2  B2   C1   D1
# 3   K1   K0  A2  B2   C2   D2
# 4   K2   K1  A3  B3  NaN  NaN

# how="right"
>>> pd.merge(left, right, how="right", on=["key1", "key2"])
#   key1 key2    A    B   C   D
# 0   K0   K0   A0   B0  C0  D0
# 1   K1   K0   A2   B2  C1  D1
# 2   K1   K0   A2   B2  C2  D2
# 3   K2   K0  NaN  NaN  C3  D3

# how="outer"
>>> pd.merge(left, right, how="outer", on=["key1", "key2"])
#   key1 key2    A    B    C    D
# 0   K0   K0   A0   B0   C0   D0
# 1   K0   K1   A1   B1  NaN  NaN
# 2   K1   K0   A2   B2   C1   D1
# 3   K1   K0   A2   B2   C2   D2
# 4   K2   K1   A3   B3  NaN  NaN
# 5   K2   K0  NaN  NaN   C3   D3

# how="inner"
>>> pd.merge(left, right, how="inner", on=["key1", "key2"])
#   key1 key2   A   B   C   D
# 0   K0   K0  A0  B0  C0  D0
# 1   K1   K0  A2  B2  C1  D1
# 2   K1   K0  A2  B2  C2  D2


# how="cross"
>>> pd.merge(left, right, how="cross")
#    key1_x key2_x   A   B key1_y key2_y   C   D
# 0      K0     K0  A0  B0     K0     K0  C0  D0
# 1      K0     K0  A0  B0     K1     K0  C1  D1
# 2      K0     K0  A0  B0     K1     K0  C2  D2
# 3      K0     K0  A0  B0     K2     K0  C3  D3
# 4      K0     K1  A1  B1     K0     K0  C0  D0
# 5      K0     K1  A1  B1     K1     K0  C1  D1
# 6      K0     K1  A1  B1     K1     K0  C2  D2
# 7      K0     K1  A1  B1     K2     K0  C3  D3
# 8      K1     K0  A2  B2     K0     K0  C0  D0
# 9      K1     K0  A2  B2     K1     K0  C1  D1
# 10     K1     K0  A2  B2     K1     K0  C2  D2
# 11     K1     K0  A2  B2     K2     K0  C3  D3
# 12     K2     K1  A3  B3     K0     K0  C0  D0
# 13     K2     K1  A3  B3     K1     K0  C1  D1
# 14     K2     K1  A3  B3     K1     K0  C2  D2
# 15     K2     K1  A3  B3     K2     K0  C3  D3

Пример с повторяющимися ключами соединения в DataFrames:

>>> left = pd.DataFrame({"A": [1, 2], "B": [2, 2]})
>>> right = pd.DataFrame({"A": [4, 5, 6], "B": [2, 2, 2]})
>>> pd.merge(left, right, on="B", how="outer")
#    A_x  B  A_y
# 0    1  2    4
# 1    1  2    5
# 2    1  2    6
# 3    2  2    4
# 4    2  2    5
# 5    2  2    6

Предупреждение. Объединение/слияние повторяющихся ключей может привести к возвращению DataFrames, который является умножением измерений строки, что может привести к переполнению памяти

Проверка ключей на дубликаты (аргумент validate)

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

В следующем примере, правый DataFrame содержит повторяющиеся значения в столбце B. Так как это не слияние один к одному, как указано в аргументе validate, будет вызвано исключение. Так как это не слияние 'one_to_one', как указано в аргументе validate, будет возбуждено исключение.

>>> pd.merge(left, right, on="B", how="outer", validate="one_to_one")
# Traceback (most recent call last):
# ...
# pandas.errors.MergeError: Merge keys are not unique in right dataset; not a one-to-one merge

Если пользователь знает о дубликатах в правом DataFrame, но хочет убедиться, что в левом DataFrame нет дубликатов, то можно использовать аргумент validate='one_to_many', который не вызовет исключения.

>>> pd.merge(left, right, on="B", how="outer", validate="one_to_many")
#    A_x  B  A_y
# 0    1  1  NaN
# 1    2  2  4.0
# 2    2  2  5.0
# 3    2  2  6.0

Индикатор слияния (аргумент indicator)

Метод DataFrame.merge() принимает аргумента indicator. Если задано значение True, то к выходному объекту будет добавлен столбец категориального типа с именем _merge, который принимает значения:

  • left_only - объединен ключ только в левом DataFrame,
  • right_only - объединен ключ только в правом DataFrame,
  • both - объединены ключи в обоих DataFrame.
>>> df1 = pd.DataFrame({"col1": [0, 1], "col_left": ["a", "b"]})
>>> df2 = pd.DataFrame({"col1": [1, 2, 2], "col_right": [2, 2, 2]})
>>> pd.merge(df1, df2, on="col1", how="outer", indicator=True)
#    col1 col_left  col_right      _merge
# 0     0        a        NaN   left_only
# 1     1        b        2.0        both
# 2     2      NaN        2.0  right_only
# 3     2      NaN        2.0  right_only

Аргумент indicator также принимает строку, и в этом случае переданная строка будет использоваться в качестве имени столбца вместо _merge.

>>> pd.merge(df1, df2, on="col1", how="outer", indicator="indicator_column")
#    col1 col_left  col_right indicator_column
# 0     0        a        NaN        left_only
# 1     1        b        2.0             both
# 2     2      NaN        2.0       right_only
# 3     2      NaN        2.0       right_only

Примеры использования DataFrame.merge():

Больше примеров смотрите в материале "Сравнение pandas с SQL"...

Создадим два DataFrame, с которыми будем работать:

import pandas as pd

df1 = pd.DataFrame({'lkey': ['foo', 'bar', 'baz', 'foo'],
                    'value': [1, 2, 3, 5]})
df2 = pd.DataFrame({'rkey': ['foo', 'bar', 'baz', 'foo'],
                    'value': [5, 6, 7, 8]})

>>> df1
#     lkey value
# 0   foo      1
# 1   bar      2
# 2   baz      3
# 3   foo      5
# df2
#     rkey value
# 0   foo      5
# 1   bar      6
# 2   baz      7
# 3   foo      8

Слияние df1 и df2 в столбцах lkey и rkey. К столбцам значений добавляются суффиксы по умолчанию, _x и _y

>>> df1.merge(df2, left_on='lkey', right_on='rkey')
#   lkey  value_x rkey  value_y
# 0  foo        1  foo        5
# 1  foo        1  foo        8
# 2  foo        5  foo        5
# 3  foo        5  foo        8
# 4  bar        2  bar        6
# 5  baz        3  baz        7

Слияние df1 и df2 с указанными левым и правым суффиксами, добавленными ко всем перекрывающимся столбцам.

>>> df1.merge(df2, left_on='lkey', right_on='rkey', suffixes=('_left', '_right'))
#   lkey  value_left rkey  value_right
# 0  foo           1  foo            5
# 1  foo           1  foo            8
# 2  foo           5  foo            5
# 3  foo           5  foo            8
# 4  bar           2  bar            6
# 5  baz           3  baz            7

Попробуем объединить df1 и df2 без указания суффиксов suffixes=(False, False), при этом поднимается исключение, если DataFrame имеют перекрывающиеся столбцы.

>>> df1.merge(df2, left_on='lkey', right_on='rkey', suffixes=(False, False))
# Traceback (most recent call last):
# ...
# ValueError: columns overlap but no suffix specified:
#     Index(['value'], dtype='object')

Для демонстрации объединения без указания суффиксов создадим новые DataFrame:

>>> df1 = pd.DataFrame({'a': ['foo', 'bar'], 'b': [1, 2]})
>>> df2 = pd.DataFrame({'a': ['foo', 'baz'], 'c': [3, 4]})
>>> df1
#       a  b
# 0   foo  1
# 1   bar  2

>>> df2
#       a  c
# 0   foo  3
# 1   baz  4

Соединение DataFrame как SQL INNER JOIN по ключу - столбец 'a':

>>> df1.merge(df2, how='inner', on='a')
#       a  b  c
# 0   foo  1  3

Соединение DataFrame как SQL LEFT OUTER JOIN по ключу - столбец 'a':

>>> df1.merge(df2, how='left', on='a')
#       a  b  c
# 0   foo  1  3.0
# 1   bar  2  NaN

Перекрестное соединение. Для большей наглядности создадим новые DataFrame:

>>> df1 = pd.DataFrame({'left': ['foo', 'bar']})
>>> df2 = pd.DataFrame({'right': [7, 8]})

>>> df1
#     left
# 0   foo
# 1   bar

>>> df2
#     right
# 0   7
# 1   8
>>> df1.merge(df2, how='cross')
#    left  right
# 0   foo      7
# 1   foo      8
# 2   bar      7
# 3   bar      8