Spec-Zone.ru › pandas 0.18

Объединение, присоединение и конкатенация

pandas предоставляет различные средства для лёгкого объединения объектов Series, DataFrame и Panel с различными типами логических операций над индексами и функциональностью реляционной алгебры в случае операций типа присоединения/слияния.

Конкатенация объектов

Функция concat (в основном пространстве имён pandas) выполняет все основные операции конкатенации вдоль оси, выполняя при этом опциональные логические операции (объединение или пересечение) индексов (если таковые имеются) на других осях. Обратите внимание, что я говорю «если таковые имеются», потому что для Series существует только одна возможная ось конкатенации.

Прежде чем углубиться во все детали concat и его возможности, вот простой пример:

In [1]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
   ...:                     'B': ['B0', 'B1', 'B2', 'B3'],
   ...:                     'C': ['C0', 'C1', 'C2', 'C3'],
   ...:                     'D': ['D0', 'D1', 'D2', 'D3']},
   ...:                     index=[0, 1, 2, 3])
   ...: 

In [2]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
   ...:                     'B': ['B4', 'B5', 'B6', 'B7'],
   ...:                     'C': ['C4', 'C5', 'C6', 'C7'],
   ...:                     'D': ['D4', 'D5', 'D6', 'D7']},
   ...:                      index=[4, 5, 6, 7])
   ...: 

In [3]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
   ...:                     'B': ['B8', 'B9', 'B10', 'B11'],
   ...:                     'C': ['C8', 'C9', 'C10', 'C11'],
   ...:                     'D': ['D8', 'D9', 'D10', 'D11']},
   ...:                     index=[8, 9, 10, 11])
   ...: 

In [4]: frames = [df1, df2, df3]

In [5]: result = pd.concat(frames)
_images/merging_concat_basic.png

Как и её аналог для массивов ndarrays, numpy.concatenate, pandas.concat принимает список или словарь однородных объектов и конкатенирует их с некоторым настраиваемым обработкой «чего делать с другими осями»:

pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
       keys=None, levels=None, names=None, verify_integrity=False)
  • objs: последовательность или отображение объектов Series, DataFrame или Panel. Если передан словарь, отсортированные ключи будут использоваться в качестве аргумента keys, если он не передан, в противном случае будут выбраны значения (см. ниже). Любые объекты None будут удалены безмолвно, за исключением случая, когда все они равны None, в этом случае будет поднято исключение ValueError.
  • axis: {0, 1, ...}, по умолчанию 0. Ось, по которой выполняется конкатенация.
  • join: {‘inner’, ‘outer’}, по умолчанию ‘outer’. Способ обработки индексов на других осях. Outer для объединения и inner для пересечения.
  • join_axes: список объектов Index. Конкретные индексы для использования на других осях n - 1 вместо выполнения логических операций inner/outer.
  • keys: последовательность, по умолчанию None. Построение иерархического индекса с использованием переданных ключей как внешнего уровня. Если передано несколько уровней, оно должно содержать кортежи.
  • levels : список последовательностей, по умолчанию None. Конкретные уровни (уникальные значения) для использования при построении MultiIndex. В противном случае они будут выведены из ключей.
  • names: список, по умолчанию None. Имена уровней в результирующем иерархическом индексе.
  • verify_integrity: булево значение, по умолчанию False. Проверка на наличие дубликатов в новой оси конкатенации. Это может быть очень дорого по сравнению с фактической конкатенацией данных.
  • ignore_index : булево значение, по умолчанию False. Если True, не использовать значения индексов на оси конкатенации. Результирующая ось будет помечена 0, ..., n - 1. Это полезно, если вы конкатенируете объекты, где ось конкатенации не имеет осмысленной информации об индексации. Обратите внимание, что значения индексов на других осях по-прежнему учитываются при объединении.
  • copy : булево значение, по умолчанию True. Если False, не копировать данные излишне.

Без небольшого контекста и примера многие из этих аргументов не имеют большого смысла. Давайте рассмотрим вышеприведённый пример. Предположим, что мы хотели связать конкретные ключи с каждой частью разбитого DataFrame. Мы можем сделать это, используя аргумент keys.

In [6]: result = pd.concat(frames, keys=['x', 'y', 'z'])
_images/merging_concat_keys.png

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

In [7]: result.ix['y']
Out[7]: 
    A   B   C   D
4  A4  B4  C4  D4
5  A5  B5  C5  D5
6  A6  B6  C6  D6
7  A7  B7  C7  D7

Несложно понять, как это может быть очень полезно. Более подробные сведения об этой функциональности приведены ниже.

Примечание

Стоит отметить, что concat (и, следовательно, append) делает полную копию данных, и постоянное повторное использование этой функции может привести к существенной потере производительности. Если вам нужно использовать операцию над несколькими наборами данных, используйте список понимания.

frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)

Логические операции над другими осями

При склеивании нескольких DataFrame (или Panel и т.д.) у вас есть выбор, как обрабатывать другие оси (кроме той, по которой выполняется конкатенация). Это можно сделать тремя способами:

  • Взять (отсортированное) объединение всех из них, join='outer'. Это вариант по умолчанию, так как он приводит к нулевым потерям информации.
  • Взять пересечение, join='inner'.
  • Использовать определённый индекс (в случае DataFrame) или индексы (в случае Panel или будущих объектов более высокой размерности), т.е. аргумент join_axes

Вот пример каждого из этих методов. Сначала поведение по умолчанию join='outer':

In [8]: df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
   ...:                  'D': ['D2', 'D3', 'D6', 'D7'],
   ...:                  'F': ['F2', 'F3', 'F6', 'F7']},
   ...:                 index=[2, 3, 6, 7])
   ...: 

In [9]: result = pd.concat([df1, df4], axis=1)
_images/merging_concat_axis1.png

Обратите внимание, что индексы строк были объединены и отсортированы. Вот то же самое с join='inner':

In [10]: result = pd.concat([df1, df4], axis=1, join='inner')
_images/merging_concat_axis1_inner.png

Наконец, предположим, что мы просто хотели использовать точный индекс из исходного DataFrame:

In [11]: result = pd.concat([df1, df4], axis=1, join_axes=[df1.index])
_images/merging_concat_axis1_join_axes.png

Конкатенация с помощью append

Полезным сокращением для concat являются методы экземпляра append для Series и DataFrame. Эти методы фактически предшествовали concat . Они конкатенируют вдоль axis=0, а именно индекса:

In [12]: result = df1.append(df2)
_images/merging_append1.png

В случае DataFrame индексы должны быть непересекающимися, но столбцы не обязательно должны быть:

In [13]: result = df1.append(df4)
_images/merging_append2.png

append может принимать несколько объектов для конкатенации:

In [14]: result = df1.append([df2, df3])
_images/merging_append3.png

Примечание

В отличие от метода list.append, который добавляет в исходный список и ничего не возвращает, append здесь **не** изменяет df1 и возвращает его копию с добавленным df2.

Игнорирование индексов на оси конкатенации

Для DataFrame, у которых нет осмысленного индекса, вы можете добавить их, игнорируя тот факт, что у них могут быть перекрывающиеся индексы:

Для этого используйте аргумент ignore_index:

In [15]: result = pd.concat([df1, df4], ignore_index=True)
_images/merging_concat_ignore_index.png

Это также допустимый аргумент для DataFrame.append:

In [16]: result = df1.append(df4, ignore_index=True)
_images/merging_append_ignore_index.png

Конкатенация с различными измерениями

Вы можете конкатенировать смесь Series и DataFrame. Series будут преобразованы в DataFrame со именем столбца как именем Series.

In [17]: s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')

In [18]: result = pd.concat([df1, s1], axis=1)
_images/merging_concat_mixed_ndim.png

Если переданы неименованные Series, они будут пронумерованы последовательно.

In [19]: s2 = pd.Series(['_0', '_1', '_2', '_3'])

In [20]: result = pd.concat([df1, s2, s2, s2], axis=1)
_images/merging_concat_unnamed_series.png

Передача ignore_index=True удалит все ссылки на имена.

In [21]: result = pd.concat([df1, s1], axis=1, ignore_index=True)
_images/merging_concat_series_ignore_index.png

Дополнительная конкатенация с ключами групп

Довольно распространённое использование аргумента keys заключается в перезаписи имён столбцов при создании нового DataFrame на основе существующих Series. Обратите внимание, как поведение по умолчанию состоит в том, чтобы позволить результирующему DataFrame унаследовать имя родительской Series, если они существовали.

In [22]: s3 = pd.Series([0, 1, 2, 3], name='foo')

In [23]: s4 = pd.Series([0, 1, 2, 3])

In [24]: s5 = pd.Series([0, 1, 4, 5])

In [25]: pd.concat([s3, s4, s5], axis=1)
Out[25]: 
   foo  0  1
0    0  0  0
1    1  1  1
2    2  2  4
3    3  3  5

С помощью аргумента keys мы можем перезаписать существующие имена столбцов.

In [26]: pd.concat([s3, s4, s5], axis=1, keys=['red','blue','yellow'])
Out[26]: 
   red  blue  yellow
0    0     0       0
1    1     1       1
2    2     2       4
3    3     3       5

Давайте рассмотрим теперь вариацию на самом первом представленном примере:

In [27]: result = pd.concat(frames, keys=['x', 'y', 'z'])
_images/merging_concat_group_keys2.png

Вы также можете передать словарь в concat, в этом случае ключи словаря будут использоваться в качестве аргумента keys (если не указаны другие ключи):

In [28]: pieces = {'x': df1, 'y': df2, 'z': df3}

In [29]: result = pd.concat(pieces)
_images/merging_concat_dict.png
In [30]: result = pd.concat(pieces, keys=['z', 'y'])
_images/merging_concat_dict_keys.png

Созданный MultiIndex имеет уровни, построенные из переданных ключей и индекса фрагментов DataFrame:

In [31]: result.index.levels
Out[31]: FrozenList([[u'z', u'y'], [4, 5, 6, 7, 8, 9, 10, 11]])

Если вы хотите указать другие уровни (что иногда бывает необходимо), вы можете сделать это, используя аргумент levels:

In [32]: result = pd.concat(pieces, keys=['x', 'y', 'z'],
   ....:                 levels=[['z', 'y', 'x', 'w']],
   ....:                 names=['group_key'])
   ....: 
_images/merging_concat_dict_keys_names.png
In [33]: result.index.levels
Out[33]: FrozenList([[u'z', u'y', u'x', u'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])

Да, это довольно экзотично, но на самом деле необходимо для реализации таких вещей, как GroupBy, где порядок категориальной переменной имеет значение.

Добавление строк в DataFrame

Хотя это не особенно эффективно (поскольку должен быть создан новый объект), вы можете добавить одну строку в DataFrame, передав Series или словарь в append, что возвращает новый DataFrame, как и выше.

In [34]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])

In [35]: result = df1.append(s2, ignore_index=True)
_images/merging_append_series_as_row.png

Вы должны использовать ignore_index с этим методом, чтобы указать DataFrame на отбрасывание его индекса. Если вы хотите сохранить индекс, вы должны создать DataFrame с соответствующим индексом и добавить или конкатенировать эти объекты.

Вы также можете передать список словарей или Series:

In [36]: dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
   ....:          {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
   ....: 

In [37]: result = df1.append(dicts, ignore_index=True)
_images/merging_append_dits.png

Объединение/слияние DataFrame в стиле баз данных

pandas имеет полнофункциональные, высокопроизводительные операции объединения в памяти, очень похожие по стилю на реляционные базы данных, такие как SQL. Эти методы работают значительно лучше (в некоторых случаях на порядок лучше), чем другие реализации с открытым исходным кодом (например, base::merge.data.frame в R). Причина в продуманном алгоритмическом проектировании и внутренней структуре данных в DataFrame.

См. справочник по рецептам для некоторых расширенных стратегий.

Пользователи, знакомые с SQL, но новые для pandas, могут быть заинтересованы в сравнении с SQL.

pandas предоставляет одну функцию, merge, как точку входа для всех стандартных операций объединения баз данных между объектами DataFrame:

merge(left, right, how='inner', on=None, left_on=None, right_on=None,
      left_index=False, right_index=False, sort=True,
      suffixes=('_x', '_y'), copy=True, indicator=False)

Вот описание того, для чего предназначен каждый аргумент:

  • left: Объект DataFrame
  • right: Другой объект DataFrame
  • on: Столбцы (имена) для объединения. Должны присутствовать в обоих объектах DataFrame. Если не передано, и left_index и right_index имеют значение False, пересечение столбцов в объектах DataFrame будет определено в качестве ключей объединения
  • left_on: Столбцы из левого объекта DataFrame для использования в качестве ключей. Могут быть именами столбцов или массивами с длиной, равной длине DataFrame
  • right_on: Столбцы из правого объекта DataFrame для использования в качестве ключей. Могут быть именами столбцов или массивами с длиной, равной длине DataFrame
  • left_index: Если True, использовать индекс (метки строк) из левого объекта DataFrame в качестве ключа(ей) объединения. В случае DataFrame с MultiIndex (иерархическим), количество уровней должно соответствовать количеству ключей объединения из правого DataFrame
  • right_index: Аналогичное использование, как у left_index для правого DataFrame
  • how: Один из 'left', 'right', 'outer', 'inner'. По умолчанию inner. См. более подробное описание каждого метода ниже
  • sort: Отсортировать результирующий DataFrame по ключам объединения в лексикографическом порядке. По умолчанию True, установка значения False существенно улучшит производительность во многих случаях
  • suffixes: Кортеж строчных суффиксов для применения к перекрывающимся столбцам. По умолчанию ('_x', '_y').
  • copy: Всегда копировать данные (по умолчанию True) из переданных объектов DataFrame, даже когда переиндексация не требуется. В многих случаях этого избежать нельзя, но эта опция может улучшить производительность/использование памяти. Случаи, когда копирование можно избежать, являются несколько патологическими, но эта опция всё же предоставляется.
  • indicator: Добавить столбец в результирующий DataFrame под названием _merge со сведениями о источнике каждой строки. _merge имеет тип Categorical и принимает значение left_only для наблюдений, ключ объединения которых встречается только в 'left' DataFrame, right_only для наблюдений, ключ объединения которых встречается только в 'right' DataFrame, и both если ключ объединения наблюдения найден в обоих.

    Добавлена в версии 0.17.0.

Тип возвращаемого значения будет таким же, как у left. Если left является DataFrame и right является подклассом DataFrame, тип возвращаемого значения всё ещё будет DataFrame.

merge — функция в пространстве имён pandas, и она также доступна в качестве метода экземпляра DataFrame, при этом вызываемый DataFrame неявно рассматривается как левый объект в объединении.

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

Краткий обзор методов объединения (реляционная алгебра)

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

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

Примечание

При объединении столбцов со столбцами (потенциально много-ко-многим объединении), любые индексы в переданных объектах DataFrame будут удалены.

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

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

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

In [40]: result = pd.merge(left, right, on='key')
_images/merging_merge_on_key.png

Вот более сложный пример с несколькими ключами объединения:

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

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

In [43]: result = pd.merge(left, right, on=['key1', 'key2'])
_images/merging_merge_on_key_multiple.png

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

Метод объединения Название объединения SQL Описание
left LEFT OUTER JOIN Использовать ключи только из левой таблицы
right RIGHT OUTER JOIN Использовать ключи только из правой таблицы
outer FULL OUTER JOIN Использовать объединение ключей из обеих таблиц
inner INNER JOIN Использовать пересечение ключей из обеих таблиц
In [44]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])
_images/merging_merge_on_key_left.png
In [45]: result = pd.merge(left, right, how='right', on=['key1', 'key2'])
_images/merging_merge_on_key_right.png
In [46]: result = pd.merge(left, right, how='outer', on=['key1', 'key2'])
_images/merging_merge_on_key_outer.png
In [47]: result = pd.merge(left, right, how='inner', on=['key1', 'key2'])
_images/merging_merge_on_key_inner.png

Индикатор объединения

Добавлена в версии 0.17.0.

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

Происхождение наблюдения _merge значение
Ключ объединения только в 'left' таблице left_only
Ключ объединения только в 'right' таблице right_only
Ключ объединения в обеих таблицах both
In [48]: df1 = DataFrame({'col1':[0,1], 'col_left':['a','b']})

In [49]: df2 = DataFrame({'col1':[1,2,2],'col_right':[2,2,2]})

In [50]: merge(df1, df2, on='col1', how='outer', indicator=True)
Out[50]: 
   col1 col_left  col_right      _merge
0   0.0        a        NaN   left_only
1   1.0        b        2.0        both
2   2.0      NaN        2.0  right_only
3   2.0      NaN        2.0  right_only

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

In [51]: merge(df1, df2, on='col1', how='outer', indicator='indicator_column')
Out[51]: 
   col1 col_left  col_right indicator_column
0   0.0        a        NaN        left_only
1   1.0        b        2.0             both
2   2.0      NaN        2.0       right_only
3   2.0      NaN        2.0       right_only

Объединение по индексу

DataFrame.join — удобный метод для объединения столбцов двух потенциально имеющих разные индексы DataFrame в единый результирующий DataFrame. Вот очень простой пример:

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

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

In [54]: result = left.join(right)
_images/merging_join.png
In [55]: result = left.join(right, how='outer')
_images/merging_join_outer.png
In [56]: result = left.join(right, how='inner')
_images/merging_join_inner.png

Выравнивание данных происходит по индексам (меткам строк). То же самое поведение можно получить, используя merge вместе с дополнительными аргументами, указывающими на использование индексов:

In [57]: result = pd.merge(left, right, left_index=True, right_index=True, how='outer')
_images/merging_merge_index_outer.png
In [58]: result = pd.merge(left, right, left_index=True, right_index=True, how='inner');
_images/merging_merge_index_inner.png

Объединение столбцов ключей по индексу

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

left.join(right, on=key_or_keys)
pd.merge(left, right, left_on=key_or_keys, right_index=True,
      how='left', sort=False)

Конечно, вы можете выбрать любую форму, которая вам удобнее. Для объединений много-к-одному (где один из DataFrame уже индексирован по ключу объединения), использование join может быть удобнее. Вот простой пример:

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

In [60]: right = pd.DataFrame({'C': ['C0', 'C1'],
   ....:                       'D': ['D0', 'D1']},
   ....:                       index=['K0', 'K1'])
   ....: 

In [61]: result = left.join(right, on='key')
_images/merging_join_key_columns.png
In [62]: result = pd.merge(left, right, left_on='key', right_index=True,
   ....:                   how='left', sort=False);
   ....: 
_images/merging_merge_key_columns.png

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

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

In [64]: index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),
   ....:                                   ('K2', 'K0'), ('K2', 'K1')])
   ....: 

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

Теперь это можно объединить, передав имена двух столбцов ключей:

In [66]: result = left.join(right, on=['key1', 'key2'])
_images/merging_join_multikeys.png

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

In [67]: result = left.join(right, on=['key1', 'key2'], how='inner')
_images/merging_join_multikeys_inner.png

Как видно, это отбрасывает строки, где не было совпадений.

Объединение по единственному индексу с многоуровневым индексом

Добавлена в версии 0.14.0.

Вы можете объединить DataFrame с одиночным индексом DataFrame с уровнем многоуровневого индекса DataFrame. Уровень будет совпадать по имени индекса одиночного DataFrame с именем уровня многоуровневого DataFrame.

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

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

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

In [71]: result = left.join(right, how='inner')
_images/merging_join_multiindex_inner.png

Это эквивалентно, но менее громоздко и более эффективно с точки зрения памяти/скорее, чем это.

In [72]: result = pd.merge(left.reset_index(), right.reset_index(),
   ....:       on=['key'], how='inner').set_index(['key','Y'])
   ....: 
_images/merging_merge_multiindex_alternative.png

Объединение с двумя многоуровневыми индексами

В данный момент это не реализовано через join, однако это можно сделать следующим образом.

In [73]: index = pd.MultiIndex.from_tuples([('K0', 'X0'), ('K0', 'X1'),
   ....:                                    ('K1', 'X2')],
   ....:                                     names=['key', 'X'])
   ....: 

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

In [75]: result = pd.merge(left.reset_index(), right.reset_index(),
   ....:                   on=['key'], how='inner').set_index(['key','X','Y'])
   ....: 
_images/merging_merge_two_multiindex.png

Перекрывающиеся столбцы значений

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

In [76]: left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})

In [77]: right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})

In [78]: result = pd.merge(left, right, on='k')
_images/merging_merge_overlapped.png
In [79]: result = pd.merge(left, right, on='k', suffixes=['_l', '_r'])
_images/merging_merge_overlapped_suffix.png

DataFrame.join имеет аргументы lsuffix и rsuffix, которые ведут себя аналогично.

In [80]: left = left.set_index('k')

In [81]: right = right.set_index('k')

In [82]: result = left.join(right, lsuffix='_l', rsuffix='_r')
_images/merging_merge_overlapped_multi_suffix.png

Объединение нескольких объектов DataFrame или Panel

Список или кортеж DataFrame также может быть передан в DataFrame.join для объединения их вместе по своим индексам. То же самое верно для Panel.join.

In [83]: right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2'])

In [84]: result = left.join([right, right2])
_images/merging_join_multi_df.png

Объединение упорядоченных данных

Новым в версии v0.8.0 является функция ordered_merge для объединения временных рядов и других упорядоченных данных. В частности, она имеет необязательный аргумент fill_method для заполнения/интерполяции пропущенных данных:

In [85]: left = DataFrame({'k': ['K0', 'K1', 'K1', 'K2'],
   ....:                   'lv': [1, 2, 3, 4],
   ....:                   's': ['a', 'b', 'c', 'd']})
   ....: 

In [86]: right = DataFrame({'k': ['K1', 'K2', 'K4'],
   ....:                    'rv': [1, 2, 3]})
   ....: 

In [87]: result = ordered_merge(left, right, fill_method='ffill', left_by='s')
_images/merging_ordered_merge.png

Объединение значений в столбцах Series или DataFrame

Еще одна довольно распространенная ситуация — это наличие двух объектов Series или DataFrame с одинаковыми индексами (или аналогичными индексами), и желание «заменить» значения в одном объекте значениями для соответствующих индексов в другом. Вот пример:

In [88]: df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],
   ....:                    [np.nan, 7., np.nan]])
   ....: 

In [89]: df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],
   ....:                    index=[1, 2])
   ....: 

Для этого используйте метод combine_first.

In [90]: result = df1.combine_first(df2)
_images/merging_combine_first.png

Обратите внимание, что этот метод берет значения только из правой DataFrame, если они отсутствуют в левой DataFrame. Связанный метод, update, изменяет значения, отличные от NA, на месте:

In [91]: df1.update(df2)
_images/merging_update.png

© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.18.1/merging.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API