Spec-Zone.ru › pandas 0.25

Слияние, объединение и конкатенация

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

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

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

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

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

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

In [7]: result.loc['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)

Логика множеств на других осях

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

  • Взять объединение всех из них, join='outer'. Это по умолчанию, так как это приводит к нулевой потере информации.
  • Взять пересечение, join='inner'.

Вот пример каждого из этих методов. Сначала поведение по умолчанию 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, sort=False)
../_images/merging_concat_axis1.png

Предупреждение

Изменено в версии 0.23.0.

Поведение по умолчанию с join='outer' — сортировать другую ось (колонки в данном случае). В будущей версии pandas по умолчанию будет не сортировать. Мы указали sort=False для того, чтобы включить новое поведение сейчас.

Вот то же самое с 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).reindex(df1.index)

Аналогично, мы могли бы индексировать перед конкатенацией:

In [12]: pd.concat([df1, df4.reindex(df1.index)], axis=1)
Out[12]: 
    A   B   C   D    B    D    F
0  A0  B0  C0  D0  NaN  NaN  NaN
1  A1  B1  C1  D1  NaN  NaN  NaN
2  A2  B2  C2  D2   B2   D2   F2
3  A3  B3  C3  D3   B3   D3   F3
../_images/merging_concat_axis1_join_axes.png

Конкатенация с использованием append

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

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

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

In [14]: result = df1.append(df4, sort=False)
../_images/merging_append2.png

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

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

Примечание

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

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

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

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

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

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

Конкатенация с смешанными ndims

Можно конкатенировать смесь Series и DataFrame объектов. Series будет преобразовано в DataFrame с именем колонки в качестве имени Series.

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

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

Примечание

Поскольку мы конкатенируем Series с DataFrame, мы могли бы достичь того же результата с помощью DataFrame.assign(). Для конкатенации произвольного числа объектов pandas (DataFrame или Series) используйте concat.

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

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

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

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

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

Более подробная конкатенация с ключами групп

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

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

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

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

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

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

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

Давайте рассмотрим изменение первого примера:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pd.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,
         validate=None)
  • left: Объект DataFrame или именованный Series.
  • right: Другой объект DataFrame или именованный Series.
  • on: Имена столбцов или уровней индексов для объединения. Должны быть найдены как в левом, так и в правом DataFrame и/или Series объектах. Если не переданы и left_index и right_index являются False, то пересечение столбцов в DataFrame и/или Series будет определено в качестве ключей объединения.
  • left_on: Столбцы или уровни индексов из левого DataFrame или Series, используемые в качестве ключей. Могут быть именами столбцов, именами уровней индекса или массивами длиной, равной длине DataFrame или Series.
  • right_on: Столбцы или уровни индексов из правого DataFrame или Series, используемые в качестве ключей. Могут быть именами столбцов, именами уровней индекса или массивами длиной, равной длине DataFrame или Series.
  • left_index: Если True, использовать индекс (метки строк) из левого DataFrame или Series в качестве ключа(ей) объединения. В случае DataFrame или Series с MultiIndex (иерархическим), количество уровней должно соответствовать количеству ключей объединения из правого DataFrame или Series.
  • right_index: То же самое использование, что и left_index для правого DataFrame или Series.
  • how: Один из 'left', 'right', 'outer', 'inner'. По умолчанию inner. См. ниже подробное описание каждого метода.
  • sort: Сортировать результирующий DataFrame по ключам объединения в лексикографическом порядке. По умолчанию True, установка в False существенно улучшает производительность во многих случаях.
  • suffixes: Кортеж строковых суффиксов, применяемых к перекрывающимся столбцам. По умолчанию ('_x', '_y').
  • copy: Всегда копировать данные (по умолчанию True) из переданных объектов DataFrame или именованных Series, даже когда переиндексация не требуется. В многих случаях избежать копирования невозможно, но этот параметр предоставляется тем не менее.
  • indicator: Добавить в результирующий DataFrame столбец, названный _merge, с информацией о происхождении каждой строки. _merge — категориального типа и принимает значение left_only для наблюдений, чей ключ объединения встречается только в 'left' DataFrame или Series, right_only для наблюдений, чей ключ объединения встречается только в 'right' DataFrame или Series, и both если ключ объединения наблюдения присутствует в обоих.
  • validate : строка, по умолчанию None. Если указано, проверяет, является ли объединение заданного типа.

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

    Введено в версии 0.21.0.

Примечание

Поддержка указания уровней индекса в качестве параметров on, left_on, и right_on была добавлена в версии 0.23.0. Поддержка объединения именованных Series объектов была добавлена в версии 0.24.0.

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

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

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

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

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

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

Примечание

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

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

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

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

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

Вот более сложный пример с несколькими ключами объединения. Только ключи, присутствующие в left и right, присутствуют (пересечение), так как how='inner' по умолчанию.

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

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

In [44]: 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 [45]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])
../_images/merging_merge_on_key_left.png
In [46]: result = pd.merge(left, right, how='right', on=['key1', 'key2'])
../_images/merging_merge_on_key_right.png
In [47]: result = pd.merge(left, right, how='outer', on=['key1', 'key2'])
../_images/merging_merge_on_key_outer.png
In [48]: result = pd.merge(left, right, how='inner', on=['key1', 'key2'])
../_images/merging_merge_on_key_inner.png

Вот еще один пример с дублирующими ключами объединения в DataFrame:

In [49]: left = pd.DataFrame({'A': [1, 2], 'B': [2, 2]})

In [50]: right = pd.DataFrame({'A': [4, 5, 6], 'B': [2, 2, 2]})

In [51]: result = pd.merge(left, right, on='B', how='outer')
../_images/merging_merge_on_key_dup.png

Предупреждение

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

Проверка на дублирующие ключи

Введено в версии 0.21.0.

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

В следующем примере есть дублирующие значения B в правом DataFrame. Поскольку это не объединение один-к-одному – как указано в аргументе validate – будет выброшено исключение.

In [52]: left = pd.DataFrame({'A' : [1,2], 'B' : [1, 2]})

In [53]: right = pd.DataFrame({'A' : [4,5,6], 'B': [2, 2, 2]})
In [53]: result = pd.merge(left, right, on='B', how='outer', validate="one_to_one")
...
MergeError: Merge keys are not unique in right dataset; not a one-to-one merge

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

In [54]: pd.merge(left, right, on='B', how='outer', validate="one_to_many")
Out[54]: 
   A_x  B  A_y
0    1  1  NaN
1    2  2  4.0
2    2  2  5.0
3    2  2  6.0

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

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

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

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

In [57]: pd.merge(df1, df2, on='col1', how='outer', indicator=True)
Out[57]: 
   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 также примет строковые аргументы, в этом случае индикаторная функция будет использовать значение переданной строки в качестве имени столбца-индикатора.

In [58]: pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')
Out[58]: 
   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

Объединение типов данных

Введено в версии 0.19.0.

Объединение сохранит тип данных ключей объединения.

In [59]: left = pd.DataFrame({'key': [1], 'v1': [10]})

In [60]: left
Out[60]: 
   key  v1
0    1  10

In [61]: right = pd.DataFrame({'key': [1, 2], 'v1': [20, 30]})

In [62]: right
Out[62]: 
   key  v1
0    1  20
1    2  30

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

In [63]: pd.merge(left, right, how='outer')
Out[63]: 
   key  v1
0    1  10
1    1  20
2    2  30

In [64]: pd.merge(left, right, how='outer').dtypes

© 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.25.0/user_guide/merging.html

Spec-Zone.ru

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