import pandas df = pandas.concat(objs, *, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=None)
objs
- принимает последовательность или словарь объектов Series
или pandas.DataFrame
. Если передан словарь, то отсортированные ключи будут использоваться в качестве аргумента keys
, если со словарем передан аргумент keys
, то в этом случае будут выбраны только значения. Любые объекты None
будут удалены автоматически. Если все значения являются None
, то в этом случае будет выдана ошибка ValueError
. axis=0
- ось для объединения. Принимает значения: 0 ('index'
) или 1 ('columns'
).join='outer'
- как обрабатывать индексы на другой оси (или осях). Принимает значения: 'inner'
или 'outer'
.ignore_index=False
- если True
, то значения индекса вдоль оси конкатенации не используются. Результирующая ось будет обозначена как 0, ..., n - 1
. Это полезно, если объединяются объекты, в которых ось конкатенации не имеет значимой информации об индексировании. Обратите внимание, что значения индексов на других осях по-прежнему учитываются при соединении.keys=None
- создает иерархический индекс, используя переданные ключи в качестве самого внешнего уровня. Если пройдено несколько уровней, должен содержать кортежи. levels=None
- конкретные уровни (уникальные значения), используемые для создания MultiIndex
. В противном случае они будут выведены из ключей.names=None
- имена уровней в результирующем иерархическом индексе.verify_integrity=False
- проверяет, нет ли дубликатов на новой объединенной оси. Это дорогостоящая операция по сравнению с фактической конкатенацией данных.sort=False
- сортирует ось перед конкатенацией, если она еще не выровнена.copy=None
- если False
, не копирует данные без необходимости.
Аргумент
copy
изменит поведение в pandas 3.0. Копирование при записи будет включено по умолчанию, а это означает, что все методы с аргументомcopy
будут использовать механизм отложенного копирования и игнорировать аргументcopy
. Ключевой аргументcopy
будет удален в будущей версииpandas
. Можно уже сейчас получить будущее поведение и улучшения, включив копирование при записиpd.options.mode.copy_on_write = True
Series
по индексу (axis=0
) возвращается Series
. Если objs
содержит хотя бы один DataFrame
, то возвращается DataFrame
. При конкатенации по столбцам (axis=1
) возвращается DataFrame
.pandas.concat()
Функция pandas.concat()
объединяет объекты pandas
вдоль определенной оси, одновременно выполняя дополнительную логику (объединение или пересечение) индексов (если таковые имеются) на других осях. Обратите внимание: на фразу "если таковые имеются", так как для Series
существует только одна возможная ось конкатенации.
Можно также добавить слой иерархической индексации на оси объединения. Это может быть полезно, если на переданной оси индексные метки совпадают (или перекрываются).
Примечание: Аргументы
keys
,levels
иnames
являются необязательными.Не рекомендуется создавать
DataFrame
, добавляя объекты вpandas.concat()
по одному в циклеfor
. Лучше построить список этих объектов и создатьDataFrame
одним вызывомpandas.concat()
.
Прежде чем останавливаться на деталях и возможностях функции pandas.concat()
смотрим простой пример:
import pandas as pd 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], ) 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], ) 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], ) >>> pd.concat([df1, df2, df3]) # A B C D # 0 A0 B0 C0 D0 # 1 A1 B1 C1 D1 # 2 A2 B2 C2 D2 # 3 A3 B3 C3 D3 # 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7 # 8 A8 B8 C8 D8 # 9 A9 B9 C9 D9 # 10 A10 B10 C10 D10 # 11 A11 B11 C11 D11
Функция pandas.concat()
принимает список или словарь однородно типизированных объектов и объединяет их с некоторой настраиваемой обработкой того, "что делать с другими осями":
Без небольшого контекста, многие из принимаемых аргументов pandas.concat()
не имеют особого смысла. Вернемся к приведенному выше примеру и предположим, что необходимо связать конкретные ключи с каждым переданным DataFrame
. Cделать это можем с помощью аргумента keys
:
>>> result = pd.concat([df1, df2, df3], keys=["x", "y", "z"]) >>> result # A B C D # x 0 A0 B0 C0 D0 # 1 A1 B1 C1 D1 # 2 A2 B2 C2 D2 # 3 A3 B3 C3 D3 # y 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7 # z 8 A8 B8 C8 D8 # 9 A9 B9 C9 D9 # 10 A10 B10 C10 D10 # 11 A11 B11 C11 D11
Видно, что индекс результирующего объекта - стал MultiIndex
. Это означает, что теперь можно выбрать каждый фрагмент по ключу. Вы не представляете, насколько это может быть полезно.
>>> result.loc["y"] # A B C D # 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7
Примечание:
pandas.concat()
создает полную копию данных и постоянное повторное использование этой функции может привести к значительному снижению производительности. Если необходимо использовать операцию над несколькими наборами данных, то лучше использовать генератор списка.# абстрактный код frames = [process_your_file(f) for f in files] result = pd.concat(frames)Примечание: при объединении
DataFrame
с именованными осями,pandas
(когда это возможно) будет пытаться сохранить эти имена индексов/столбцов. В случае, когда все входные данные имеют общее имя, то это имя будет присвоено результату. Если имена входных данных не совпадают, то результат будет без имени. То же самое справедливо и дляMultiIndex
, но логика применяется отдельно, уровень за уровнем.
При склеивании нескольких DataFrames
есть выбор способа обработки других осей (кроме объединяемой). Это можно сделать двумя способами:
join='inner'
join='outer'
. Это вариант по умолчанию, так как он приводит к нулевой потере информации.Поведение каждого из этих методов. Пример поведения join='outer'
(по умолчанию):
df4 = pd.DataFrame( { "B": ["B2", "B3", "B6", "B7"], "D": ["D2", "D3", "D6", "D7"], "F": ["F2", "F3", "F6", "F7"], }, index=[2, 3, 6, 7], ) >>> pd.concat([df1, df4], axis=1) # 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 # 6 NaN NaN NaN NaN B6 D6 F6 # 7 NaN NaN NaN NaN B7 D7 F7
Теперь то же самое, но с join='inner'
:
>>> pd.concat([df1, df4], axis=1, join="inner") # A B C D B D F # 2 A2 B2 C2 D2 B2 D2 F2 # 3 A3 B3 C3 D3 B3 D3 F3
Наконец, предположим, что нужно повторно использовать точный индекс из исходного DataFrame
:
>>> pd.concat([df1, df4], axis=1).reindex(df1.index) # 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 # Точно так же можно индексировать перед конкатенацией: >>> pd.concat([df1, df4.reindex(df1.index)], axis=1) # 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
Для объектов DataFrame
, у которых индекс не несет смысловой нагрузки, можно игнорировать тот факт, что они могут перекрываться. Для этого используем аргумент ignore_index
:
>>> pd.concat([df1, df4], ignore_index=True, sort=False) # A B C D F # 0 A0 B0 C0 D0 NaN # 1 A1 B1 C1 D1 NaN # 2 A2 B2 C2 D2 NaN # 3 A3 B3 C3 D3 NaN # 4 NaN B2 NaN D2 F2 # 5 NaN B3 NaN D3 F3 # 6 NaN B6 NaN D6 F6 # 7 NaN B7 NaN D7 F7
Series
и DataFrame
Можно объединить сочетание объектов Series
и DataFrame
. Серия будет преобразована в DataFrame
с именем столбца, считанное из Series.name
.
>>> s1 = pd.Series(["X0", "X1", "X2", "X3"], name="X") >>> s1.name # 'X' >>> pd.concat([df1, s1], axis=1) # A B C D X # 0 A0 B0 C0 D0 X0 # 1 A1 B1 C1 D1 X1 # 2 A2 B2 C2 D2 X2 # 3 A3 B3 C3 D3 X3
Заметка. Так как объединяется
Series
вDataFrame
, то этого результата можно достичь с помощьюDataFrame.assign()
. Чтобы объединить произвольное количество объектовpandas
(DataFrame
илиSeries
), необходимо использовать функциюpandas.concat()
.
Если передаются Series
, у которых не задан атрибут Series.name
, то они будут пронумерованы последовательно.
>>> s2 = pd.Series(["_0", "_1", "_2", "_3"]) >>> pd.concat([df1, s2, s2, s2], axis=1) # A B C D 0 1 2 # 0 A0 B0 C0 D0 _0 _0 _0 # 1 A1 B1 C1 D1 _1 _1 _1 # 2 A2 B2 C2 D2 _2 _2 _2 # 3 A3 B3 C3 D3 _3 _3 _3
Передача ignore_index=True
приведет к удалению всех ссылок на имена. Обратите внимание на индексные метки строк/столбцов.
>>> pd.concat([df1, s1], axis=1, ignore_index=True) # 0 1 2 3 4 # 0 A0 B0 C0 D0 X0 # 1 A1 B1 C1 D1 X1 # 2 A2 B2 C2 D2 X2 # 3 A3 B3 C3 D3 X3
Распространенным использованием аргумента keys
является переопределение имен столбцов при создании нового DataFrame
на основе существующего Series
. Заметьте, что поведение по умолчанию заключается в том, что результирующий DataFrame
наследует имена родительских Series
, когда они существуют.
>>> s3 = pd.Series([0, 1, 2, 3], name="foo") >>> s4 = pd.Series([0, 1, 2, 3]) >>> s5 = pd.Series([0, 1, 4, 5]) >>> pd.concat([s3, s4, s5], axis=1) # foo 0 1 # 0 0 0 0 # 1 1 1 1 # 2 2 2 4 # 3 3 3 5
С помощью аргумента keys
можно переопределить существующие имена столбцов.
>>> pd.concat([s3, s4, s5], axis=1, keys=["red", "blue", "yellow"]) # red blue yellow # 0 0 0 0 # 1 1 1 1 # 2 2 2 4 # 3 3 3 5
Рассмотрим вариацию самого первого примера:
>>> frames = [df1, df2, df3] >>> pd.concat(frames, keys=["x", "y", "z"]) # эквивалентно >>> mapping = {"x": df1, "y": df2, "z": df3} >>> pd.concat(mapping) # A B C D # x 0 A0 B0 C0 D0 # 1 A1 B1 C1 D1 # 2 A2 B2 C2 D2 # 3 A3 B3 C3 D3 # y 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7 # z 8 A8 B8 C8 D8 # 9 A9 B9 C9 D9 # 10 A10 B10 C10 D10 # 11 A11 B11 C11 D11 >>> result = pd.concat(mapping, keys=["z", "y"]) # A B C D # z 8 A8 B8 C8 D8 # 9 A9 B9 C9 D9 # 10 A10 B10 C10 D10 # 11 A11 B11 C11 D11 # y 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7
Созданный MultiIndex
имеет уровни, которые строятся из переданных ключей и индекса фрагментов DataFrame
:
>>> result.index.levels # FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
Если нужно указать другие уровни (что иногда случается), то можно сделать это с помощью аргумента levels
:
result = pd.concat( mapping, keys=["x", "y", "z"], levels=[["z", "y", "x", "w"]], names=["group_key"] ) >>> result # A B C D # group_key # x 0 A0 B0 C0 D0 # 1 A1 B1 C1 D1 # 2 A2 B2 C2 D2 # 3 A3 B3 C3 D3 # y 4 A4 B4 C4 D4 # 5 A5 B5 C5 D5 # 6 A6 B6 C6 D6 # 7 A7 B7 C7 D7 # z 8 A8 B8 C8 D8 # 9 A9 B9 C9 D9 # 10 A10 B10 C10 D10 # 11 A11 B11 C11 D11
>>> result.index.levels # FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
Это немного непонятно, но на самом деле необходимо для реализации GroupBy
, где порядок "категориальной" переменной имеет смысл.
Если есть ряд, который необходимо добавить как одну строку в DataFrame
, то можно преобразовать строку в DataFrame
>>> s2 = pd.Series(["X0", "X1", "X2", "X3"], index=["A", "B", "C", "D"]) >>> pd.concat([df1, s2.to_frame().T], ignore_index=True) # A B C D # 0 A0 B0 C0 D0 # 1 A1 B1 C1 D1 # 2 A2 B2 C2 D2 # 3 A3 B3 C3 D3 # 4 X0 X1 X2 X3 (добавленная строка)
Чтобы DataFrame
удалил свой индекс, нужно использовать аргумент ignore_index
. Если необходимо сохранить индекс, то нужно создать соответствующим образом индексированный DataFrame
и добавить или объединить эти объекты.
pandas.concat()
Объединение двух Series
.
>>> s1 = pd.Series(['a', 'b']) >>> s2 = pd.Series(['c', 'd']) >>> pd.concat([s1, s2]) # 0 a # 1 b # 0 c # 1 d # dtype: object
Очистим и сбросим существующий индекс, установив аргумент ignore_index=True
.
>>> pd.concat([s1, s2], ignore_index=True) # 0 a # 1 b # 2 c # 3 d # dtype: object
Добавим MultiIndex
на самом внешнем уровне данных с помощью аргумента keys
.
>>> pd.concat([s1, s2], keys=['s1', 's2']) # s1 0 a # 1 b # s2 0 c # 1 d # dtype: object
Добавим имена индексным ключам, используя аргумент names
.
>>> pd.concat([s1, s2], keys=['s1', 's2'], names=['Series name', 'Row ID']) # Series name Row ID # s1 0 a # 1 b # s2 0 c # 1 d # dtype: object
Объединяем два объекта DataFrame
с одинаковыми столбцами.
>>> df1 = pd.DataFrame([['a', 1], ['b', 2]], columns=['letter', 'number']) >>> df2 = pd.DataFrame([['c', 3], ['d', 4]], columns=['letter', 'number']) >>> df1 # letter number # 0 a 1 # 1 b 2 >>> df2 # letter number # 0 c 3 # 1 d 4 >>> pd.concat([df1, df2]) # letter number # 0 a 1 # 1 b 2 # 0 c 3 # 1 d 4
Объединяем объекты DataFrame
с перекрывающимися столбцами. Столбцы за пределами пересечения будут заполнены значениями NaN
.
>>> df3 = pd.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']], columns=['letter', 'number', 'animal']) >>> df3 # letter number animal # 0 c 3 cat # 1 d 4 dog >>> pd.concat([df1, df3], sort=False) # letter number animal # 0 a 1 NaN # 1 b 2 NaN # 0 c 3 cat # 1 d 4 dog
Объединим объекты DataFrame
с перекрывающимися столбцами и получим только те, которые являются общими, передав аргумент join='inner'
.
>>> pd.concat([df1, df3], join="inner") # letter number # 0 a 1 # 1 b 2 # 0 c 3 # 1 d 4
Объедините объекты DataFrame
по горизонтали вдоль оси x
, передав axis=1
.
>>> df4 = pd.DataFrame([['bird', 'polly'], ['monkey', 'george']], columns=['animal', 'name']) >>> df4 # animal name # 0 bird polly # 1 monkey george >>> pd.concat([df1, df4], axis=1) # letter number animal name # 0 a 1 bird polly # 1 b 2 monkey george
Аргумента verify_integrity
отвечает за проверку на дубликаты меток индекса в результирующем DataFrame
и если они будут, то поднимает исключение ValueError
.
>>> df5 = pd.DataFrame([1], index=['a']) >>> df6 = pd.DataFrame([2], index=['a']) >>> df5 # 0 # a 1 >>> df6 # 0 # a 2 >>> pd.concat([df5, df6], verify_integrity=True) # Traceback (most recent call last): # ... # ValueError: Indexes have overlapping values: ['a']
Добавим одну строку в конец объекта DataFrame
.
>>> df7 = pd.DataFrame({'a': 1, 'b': 2}, index=[0]) >>> df7 # a b # 0 1 2 >>> new_row = pd.Series({'a': 3, 'b': 4}) >>> new_row # a 3 # b 4 # dtype: int64 >>> pd.concat([df7, new_row.to_frame().T], ignore_index=True) # a b # 0 1 2 # 1 3 4