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

Метод DataFrame.join() в pandas, объединение DataFrame

Объединение столбцов с другим DataFrame по индексу/столбцу

Синтаксис:

df_join = DataFrame.join(other, on=None, how='left', lsuffix='', 
                         rsuffix='', sort=False, validate=None)

Параметры:

  • other - DataFrame, Series или список, содержащий любую их комбинацию. Индексом должен быть одним из столбцов. Если передается Series, то должен быть установлен его атрибут Series.name, который будет использоваться в качестве имени столбца в результирующем объединенном DataFrame.

  • on=None - строка с именем столбца, список имен столбцов или уровней индекса в исходном/вызывающем DataFrame для присоединения к индексу в other, в противном случае присоединяются индекс к индексу. Если задано несколько значений, то другой DataFrame (other) должен иметь MultiIndex. Можно передать массив в качестве ключа соединения, если он еще не содержится в вызывающем DataFrame. Типа операции VLOOKUP в Excel.

    Не поддерживаются при передаче списка объектов в other.

  • how='left' - управляет объединением двух объектов.

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

    • left: использовать индекс вызывающего DataFrame (или столбец, если указан on)
    • right: использовать индекс other.
    • outer: сформировать объединение индекса вызывающего DataFrame (или столбца, если указан on) с индексом other и отсортировать его лексикографически.
    • inner: форма пересечения индекса вызывающего DataFrame (или столбца, если указан on) с индексом other, при этом сохранить порядок вызывающего DataFrame.
    • cross: создает декартово произведение из обоих DataFrame, сохраняет порядок левых ключей.

  • lsuffix='' - суффикс, используемый из перекрывающихся столбцов левого DataFrame. Не поддерживаются при передаче списка объектов в other.

  • rsuffix='' - суффикс, используемый из перекрывающихся столбцов правого DataFrame. Не поддерживаются при передаче списка объектов в other.

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

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

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

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

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

  • DataFrame, содержащий столбцы как от вызывающего DataFrame, так и от другого DataFrame/Series.

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

Метод DataFrame.join() модуля pandas эффективно объединяет столбцы с другим DataFrame либо по индексу, либо по ключевому столбцу. Поддерживает объединение по индексу, одновременно с несколькими объектами DataFrame/Series.

Другими словами - это удобный метод объединения столбцов двух потенциально по-разному индексированных DataFrame в единый результирующий фрейм данных.

Простой пример:

>>> import pandas as pd

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

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

>>> left.join(right)
#      A   B    C    D
# K0  A0  B0   C0   D0
# K1  A1  B1  NaN  NaN
# K2  A2  B2   C2   D2

То же, что и выше, только с аргументом how="inner" (пересечения индекса)

>>> left.join(right, how="inner")
#      A   B   C   D
# K0  A0  B0  C0  D0
# K2  A2  B2  C2  D2

Объединение ключевых столбцов в индексе

Метод DataFrame.join() принимает необязательный аргумент on, который может быть именем столбца или нескольких столбцов, и указывает, что переданный DataFrame должен быть выровнен по этому столбцу. Следующие два вызова полностью эквивалентны:

# абстрактный код
left.join(right, on=key_or_keys)

# эквивалентно (вызов делает то-же самое)
left.merge(
    right, left_on=key_or_keys, right_index=True, how="left", sort=False
)

Для соединений 'many-to-one' (когда один из DataFrame уже проиндексирован по ключу соединения) использование метода DataFrame.join() может быть более удобным. Простой пример:

>>> left = pd.DataFrame({"A": ["A0", "A1", "A2", "A3"], "B": ["B0", "B1", "B2", "B3"], 
...                      "key": ["K0", "K1", "K0", "K1"],})
>>> right = pd.DataFrame({"C": ["C0", "C1"], "D": ["D0", "D1"]}, index=["K0", "K1"])
>>> left.join(right, on="key")
#     A   B key   C   D
# 0  A0  B0  K0  C0  D0
# 1  A1  B1  K1  C1  D1
# 2  A2  B2  K0  C0  D0
# 3  A3  B3  K1  C1  D1

>>> left.merge(right, left_on="key", right_index=True, how="left", sort=False)
#     A   B key   C   D
# 0  A0  B0  K0  C0  D0
# 1  A1  B1  K1  C1  D1
# 2  A2  B2  K0  C0  D0
# 3  A3  B3  K1  C1  D1

Для соединения по нескольким ключам, переданный DataFrame должен иметь MultiIndex. Для демонстрации примера создадим DataFrame c MultiIndex:

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

index = pd.MultiIndex.from_tuples(
    [("K0", "K0"), ("K1", "K0"), ("K2", "K0"), ("K2", "K1")]
)

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

Теперь созданные DataFrame можно соединить, передав два имени столбца, используемых как ключи аргумента on:

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

По умолчанию для DataFrame.join() выполняется левое соединение (по сути, операция VLOOKUP в Excel), в котором используются только ключи, найденные в вызывающем DataFrame. Другие типы соединений, например, внутреннее соединение, могут быть выполнены так же легко:

>>> left.join(right, on=["key1", "key2"], how="inner")
#     A   B key1 key2   C   D
# 0  A0  B0   K0   K0  C0  D0
# 2  A2  B2   K1   K0  C1  D1
# 3  A3  B3   K2   K1  C3  D3

При этом отбрасываются все строки, в которых не было совпадений.

Присоединение простого индекса к MultiIndex

DataFrame с простым индексом можно объединить с помощью уровня MultiIndex. Уровень будет совпадать по имени индекса простого DataFrame с именем уровня MultiIndex (другой DataFrame).

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

index = pd.MultiIndex.from_tuples(
    [("K0", "Y0"), ("K1", "Y1"), ("K2", "Y2"), ("K2", "Y3")],
    names=["key", "Y"],
)

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

>>> left.join(right, how="inner")
#          A   B   C   D
# key Y                 
# K0  Y0  A0  B0  C0  D0
# K1  Y1  A1  B1  C1  D1
# K2  Y2  A2  B2  C2  D2
#     Y3  A2  B2  C3  D3

Объединение двух DataFrame с MultiIndex

Такое поведение поддерживается ограниченным образом, при условии, что индекс в правом DataFrame полностью используется в соединении и является подмножеством индексов в левом DataFrame, как в этом примере:

leftindex = pd.MultiIndex.from_product(
    [list("abc"), list("xy"), [1, 2]], names=["abc", "xy", "num"]
)
>>> left = pd.DataFrame({"v1": range(12)}, index=leftindex)
>>> left
#             v1
# abc xy num    
# a   x  1     0
#        2     1
#     y  1     2
#        2     3
# b   x  1     4
#        2     5
#     y  1     6
#        2     7
# c   x  1     8
#        2     9
#     y  1    10
#        2    11

rightindex = pd.MultiIndex.from_product(
    [list("abc"), list("xy")], names=["abc", "xy"]
)
>>> right = pd.DataFrame({"v2": [100 * i for i in range(1, 7)]}, index=rightindex)
>>> right
#          v2
# abc xy     
# a   x   100
#     y   200
# b   x   300
#     y   400
# c   x   500
#     y   600

left.join(right, on=["abc", "xy"], how="inner")
#             v1   v2
# abc xy num         
# a   x  1     0  100
#        2     1  100
#     y  1     2  200
#        2     3  200
# b   x  1     4  300
#        2     5  300
#     y  1     6  400
#        2     7  400
# c   x  1     8  500
#        2     9  500
#     y  1    10  600
#        2    11  600

Если это условие не выполняется, соединение двух DataFrame, имеющих MultiIndex можно выполнить с помощью DataFrame.merge().

leftindex = pd.MultiIndex.from_tuples(
    [("K0", "X0"), ("K0", "X1"), ("K1", "X2")], names=["key", "X"]
)

left = pd.DataFrame(
    {"A": ["A0", "A1", "A2"], "B": ["B0", "B1", "B2"]}, index=leftindex
)

rightindex = pd.MultiIndex.from_tuples(
    [("K0", "Y0"), ("K1", "Y1"), ("K2", "Y2"), ("K2", "Y3")], names=["key", "Y"]
)

right = pd.DataFrame(
    {"C": ["C0", "C1", "C2", "C3"], "D": ["D0", "D1", "D2", "D3"]}, index=rightindex
)

>>> left.reset_index().merge(right.reset_index(), on=["key"], how="inner").set_index(["key", "X", "Y"])
#             A   B   C   D
# key X  Y                 
# K0  X0 Y0  A0  B0  C0  D0
#     X1 Y0  A1  B1  C0  D0
# K1  X2 Y1  A2  B2  C1  D1

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

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

Необходимо помнить, что аргументы on, lsuffix и rsuffix не поддерживаются при передаче списка объектов DataFrame аргументу other.

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

import pandas as pd

df = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'],
                   'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})

other = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
                      'B': ['B0', 'B1', 'B2']})

>>> df
#   key   A
# 0  K0  A0
# 1  K1  A1
# 2  K2  A2
# 3  K3  A3
# 4  K4  A4
# 5  K5  A5

>>> other
#   key   B
# 0  K0  B0
# 1  K1  B1
# 2  K2  B2

Присоединим other к df, используя их индексы.

>>> df.join(other, lsuffix='_caller', rsuffix='_other')
#   key_caller   A key_other    B
# 0         K0  A0        K0   B0
# 1         K1  A1        K1   B1
# 2         K2  A2        K2   B2
# 3         K3  A3       NaN  NaN
# 4         K4  A4       NaN  NaN
# 5         K5  A5       NaN  NaN

Если необходимо объединение, используя ключевые столбцы, то нужно установить ключ в качестве индекса как в df, так и в other. Результирующий DataFrame будет иметь в качестве индекса - ключ.

>>> df.set_index('key').join(other.set_index('key'))
#       A    B
# key         
# K0   A0   B0
# K1   A1   B1
# K2   A2   B2
# K3   A3  NaN
# K4   A4  NaN
# K5   A5  NaN

Другой вариант объединения с использованием ключевых столбцов - использование аргумента on. DataFrame.join() всегда использует индекс из other, при этом можно указать (аргумент on) любой столбец (в качестве ключа) из df. В результате, метод сохранит индекс исходного DataFrame.

>>> df.join(other.set_index('key'), on='key')
#   key   A    B
# 0  K0  A0   B0
# 1  K1  A1   B1
# 2  K2  A2   B2
# 3  K3  A3  NaN
# 4  K4  A4  NaN
# 5  K5  A5  NaN

Объединение DataFrame, у которых есть повторяющиеся (неуникальные) значения ключа. Смотрим как они сопоставляются. Для этого создадим DataFrame с повторяющимися значениями:

df = pd.DataFrame({'key': ['K0', 'K1', 'K1', 'K3', 'K0', 'K1'],
                   'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})

>>> df
#   key   A
# 0  K0  A0
# 1  K1  A1
# 2  K1  A2
# 3  K3  A3
# 4  K0  A4
# 5  K1  A5

>>> other
#   key   B
# 0  K0  B0
# 1  K1  B1
# 2  K2  B2

# объединяем
>>> df.join(other.set_index('key'), on='key', validate='m:1')
#   key   A    B
# 0  K0  A0   B0
# 1  K1  A1   B1
# 2  K1  A2   B1
# 3  K3  A3  NaN
# 4  K0  A4   B0
# 5  K1  A5   B1