Каковы аргументы «уровни», «ключи» и имена в функции concat Pandas?

97

Вопросы

  • Как пользоваться pd.concat?
  • Для чего levelsнужен аргумент?
  • Для чего keysнужен аргумент?
  • Есть несколько примеров, которые помогут объяснить, как использовать все аргументы?

concatФункция Pandas - это швейцарский армейский нож сливающихся утилит. Разнообразие ситуаций, в которых она может быть полезна, велико. В существующей документации отсутствуют некоторые подробности некоторых дополнительных аргументов. Среди них levelsи keysаргументы. Я решил выяснить, что делают эти аргументы.

Я задам вопрос, который послужит входом во многие аспекты pd.concat .

Рассмотрим кадры данных d1, d2и d3:

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), [2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), [1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), [1, 3])

Если бы я объединил их вместе с

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'])

Я получаю ожидаемый результат с помощью pandas.MultiIndexдля своего columnsобъекта:

        A    B    C    D
d1 2  0.1  0.2  0.3  NaN
   3  0.1  0.2  0.3  NaN
d2 1  NaN  0.4  0.5  0.6
   2  NaN  0.4  0.5  0.6
d3 1  0.7  0.8  NaN  0.9
   3  0.7  0.8  NaN  0.9

Однако я хотел использовать levelsдокументацию по аргументам :

уровни : список последовательностей, по умолчанию Нет. Конкретные уровни (уникальные значения) для использования при построении MultiIndex. В противном случае они будут выведены из ключей.

Так я прошел

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2']])

И получить KeyError

ValueError: Key d3 not in level Index(['d1', 'd2'], dtype='object')

В этом был смысл. Уровни, которые я прошел, были недостаточны для описания необходимых уровней, обозначенных клавишами. Если бы я ничего не прошел, как я сделал выше, уровни предполагаются (как указано в документации). Но как еще я могу использовать этот аргумент для большего эффекта?

Если бы я попробовал это вместо этого:

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3']])

Я и получил те же результаты, что и выше. Но когда я добавляю еще одно значение к уровням,

df = pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3', 'd4']])

Я получаю такой же фрейм данных, но в результате MultiIndexостается неиспользуемый уровень.

df.index.levels[0]

Index(['d1', 'd2', 'd3', 'd4'], dtype='object')

Итак, в чем суть levelаргумента и следует ли мне использоватьkeys другому?

Я использую Python 3.6 и Pandas 0.22.

PiRSquared
источник

Ответы:

129

Отвечая на этот вопрос для себя, я многому научился и хотел составить каталог примеров и некоторые объяснения.

Конкретный ответ на суть levelsспора будет ближе к концу.

pandas.concat: Пропавшее руководство

Ссылка на текущую документацию

Импорт и определение объектов

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), index=[2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), index=[1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), index=[1, 3])

s1 = pd.Series([1, 2], index=[2, 3])
s2 = pd.Series([3, 4], index=[1, 2])
s3 = pd.Series([5, 6], index=[1, 3])

Аргументы

objs

Первый аргумент, с которым мы сталкиваемся objs:

objs : последовательность или отображение объектов Series, DataFrame или Panel. Если передан dict, отсортированные ключи будут использоваться в качестве аргумента ключей, если он не передан, и в этом случае будут выбраны значения (см. ниже). Любые объекты None будут отброшены без уведомления, если только они не все None, и в этом случае будет вызвана ошибка ValueError.

  • Обычно мы видим, что это используется со списком объектов Seriesили DataFrame.
  • Я покажу это dict тоже может быть очень полезно.
  • Генераторы также могут быть использованы и могут быть полезны при использовании mapкак вmap(f, list_of_df)

На данный момент, мы будем придерживаться список некоторых из DataFrameи Seriesобъекты , определенные выше. MultiIndexПозже я покажу, как можно использовать словари для получения очень полезных результатов.

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

axis

Второй аргумент, с которым мы сталкиваемся, имеет axisзначение по умолчанию 0:

ось : {0 / 'index', 1 / 'columns'}, по умолчанию 0 Ось для объединения.

Два DataFrameсaxis=0 (сложены)

Для значений 0илиindex мы имеем в виду: «Выровнять по столбцам и добавить в индекс».

Как показано выше, где мы использовали axis=0, потому что 0это значение по умолчанию, и мы видим, что индекс d2расширяет индекс, d1несмотря на перекрытие значений 2:

pd.concat([d1, d2], axis=0)

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

Два DataFrameс axis=1(бок о бок)

Для значений 1или columnsмы хотим сказать: «Выровнять по индексу и добавить в столбцы»,

pd.concat([d1, d2], axis=1)

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

Мы можем видеть, что результирующий индекс представляет собой объединение индексов, а результирующие столбцы являются расширением столбцов из d1столбцами d2.

Два (или три) Seriesс axis=0(сложенными)

При объединении pandas.Seriesвместе axis=0, мы получаем обратно pandas.Series. Имя результата Seriesбудет, Noneесли все Seriesобъединенные не будут иметь одинаковое имя. Обратите внимание на то, 'Name: A'когда мы распечатываем результат Series. Когда его нет, мы можем предположить, что Seriesимя есть None.

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('A'),
 pd.concat(    |      [s1.rename('A'), |      [s1.rename('A'),  |       s2.rename('B'),
     [s1, s2]) |       s2])            |       s2.rename('A')]) |       s3.rename('A')])
-------------- | --------------------- | ---------------------- | ----------------------
2    1         | 2    1                | 2    1                 | 2    1
3    2         | 3    2                | 3    2                 | 3    2
1    3         | 1    3                | 1    3                 | 1    3
2    4         | 2    4                | 2    4                 | 2    4
dtype: int64   | dtype: int64          | Name: A, dtype: int64  | 1    5
               |                       |                        | 3    6
               |                       |                        | dtype: int64

Два (или Три) Seriesс axis=1(рядом)

При объединении pandas.Seriesвместе axis=1, это nameатрибут , который мы называем для того , чтобы вывести имя столбца в результирующем pandas.DataFrame.

                       |                       |  pd.concat(
                       |  pd.concat(           |      [s1.rename('X'),
 pd.concat(            |      [s1.rename('X'), |       s2.rename('Y'),
     [s1, s2], axis=1) |       s2], axis=1)    |       s3.rename('Z')], axis=1)
---------------------- | --------------------- | ------------------------------
     0    1            |      X    0           |      X    Y    Z
1  NaN  3.0            | 1  NaN  3.0           | 1  NaN  3.0  5.0
2  1.0  4.0            | 2  1.0  4.0           | 2  1.0  4.0  NaN
3  2.0  NaN            | 3  2.0  NaN           | 3  2.0  NaN  6.0

Смешанные Seriesи DataFrameс axis=0(сложенные)

При выполнении конкатенации a Seriesи DataFrameвместе axis=0мы конвертируем все Seriesв один столбец DataFrames.

Обратите особое внимание на то, что это объединение вместе axis=0; это означает расширение индекса (строк) при выравнивании столбцов. В приведенных ниже примерах мы видим, что индекс превращается [2, 3, 2, 3]в неразборчивое добавление индексов. Столбцы не перекрываются, если я не принудительно назвал Seriesстолбец с аргументом to_frame:

 pd.concat(               |
     [s1.to_frame(), d1]) |  pd.concat([s1, d1])
------------------------- | ---------------------
     0    A    B    C     |      0    A    B    C
2  1.0  NaN  NaN  NaN     | 2  1.0  NaN  NaN  NaN
3  2.0  NaN  NaN  NaN     | 3  2.0  NaN  NaN  NaN
2  NaN  0.1  0.2  0.3     | 2  NaN  0.1  0.2  0.3
3  NaN  0.1  0.2  0.3     | 3  NaN  0.1  0.2  0.3

Вы можете видеть, что результаты pd.concat([s1, d1])такие же, как если бы я делал to_frameсам.

Однако я могу контролировать имя результирующего столбца с помощью параметра to_frame. Переименование Seriesс помощью renameметода не влияет на имя столбца в результате DataFrame.

 # Effectively renames       |                            |
 # `s1` but does not align   |  # Does not rename.  So    |  # Renames to something
 # with columns in `d1`      |  # Pandas defaults to `0`  |  # that does align with `d1`
 pd.concat(                  |  pd.concat(                |  pd.concat(
     [s1.to_frame('X'), d1]) |      [s1.rename('X'), d1]) |      [s1.to_frame('B'), d1])
---------------------------- | -------------------------- | ----------------------------
     A    B    C    X        |      0    A    B    C      |      A    B    C
2  NaN  NaN  NaN  1.0        | 2  1.0  NaN  NaN  NaN      | 2  NaN  1.0  NaN
3  NaN  NaN  NaN  2.0        | 3  2.0  NaN  NaN  NaN      | 3  NaN  2.0  NaN
2  0.1  0.2  0.3  NaN        | 2  NaN  0.1  0.2  0.3      | 2  0.1  0.2  0.3
3  0.1  0.2  0.3  NaN        | 3  NaN  0.1  0.2  0.3      | 3  0.1  0.2  0.3

Смешанные Seriesи DataFrameс axis=1(рядом)

Это довольно интуитивно понятно. Seriesимя столбца по умолчанию представляет собой перечисление таких Seriesобъектов, когда nameатрибут недоступен.

                    |  pd.concat(
 pd.concat(         |      [s1.rename('X'),
     [s1, d1],      |       s2, s3, d1],
     axis=1)        |      axis=1)
------------------- | -------------------------------
   0    A    B    C |      X    0    1    A    B    C
2  1  0.1  0.2  0.3 | 1  NaN  3.0  5.0  NaN  NaN  NaN
3  2  0.1  0.2  0.3 | 2  1.0  4.0  NaN  0.1  0.2  0.3
                    | 3  2.0  NaN  6.0  0.1  0.2  0.3

join

Третий аргумент joinописывает, должно ли полученное слияние быть внешним (по умолчанию) или внутренним.

join : {'внутренний', 'внешний'}, по умолчанию 'внешний'
Как обрабатывать индексы на другой оси (осях).

Оказывается, нет опции leftили, чтобы объединить более двух объектов.rightpd.concat

В случае d1и d2варианты выглядят так:

outer

pd.concat([d1, d2], axis=1, join='outer')

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

inner

pd.concat([d1, d2], axis=1, join='inner')

     A    B    C    B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6

join_axes

Четвертый аргумент - это то, что позволяет нам делать наше leftслияние и многое другое.

join_axes : список объектов
индекса. Конкретные индексы для использования для других осей n - 1 вместо выполнения логики внутреннего / внешнего набора.

Левое слияние

pd.concat([d1, d2, d3], axis=1, join_axes=[d1.index])

     A    B    C    B    C    D    A    B    D
2  0.1  0.2  0.3  0.4  0.5  0.6  NaN  NaN  NaN
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

Правое слияние

pd.concat([d1, d2, d3], axis=1, join_axes=[d3.index])

     A    B    C    B    C    D    A    B    D
1  NaN  NaN  NaN  0.4  0.5  0.6  0.7  0.8  0.9
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

ignore_index

ignore_index : boolean, по умолчанию - False.
Если True, не использовать значения индекса по оси конкатенации. Результирующая ось будет помечена 0, ..., n - 1. Это полезно, если вы объединяете объекты, у которых ось объединения не имеет значимой информации для индексации. Обратите внимание, что значения индексов на других осях по-прежнему учитываются при объединении.

Например, когда я складываюсь d1поверх d2, если меня не волнуют значения индекса, я могу сбросить их или игнорировать.

                      |  pd.concat(             |  pd.concat(
                      |      [d1, d2],          |      [d1, d2]
 pd.concat([d1, d2])  |      ignore_index=True) |  ).reset_index(drop=True)
--------------------- | ----------------------- | -------------------------
     A    B    C    D |      A    B    C    D   |      A    B    C    D
2  0.1  0.2  0.3  NaN | 0  0.1  0.2  0.3  NaN   | 0  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN | 1  0.1  0.2  0.3  NaN   | 1  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6 | 2  NaN  0.4  0.5  0.6   | 2  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6 | 3  NaN  0.4  0.5  0.6   | 3  NaN  0.4  0.5  0.6

И при использовании axis=1:

                                   |     pd.concat(
                                   |         [d1, d2], axis=1,
 pd.concat([d1, d2], axis=1)       |         ignore_index=True)
-------------------------------    |    -------------------------------
     A    B    C    B    C    D    |         0    1    2    3    4    5
1  NaN  NaN  NaN  0.4  0.5  0.6    |    1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6    |    2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN    |    3  0.1  0.2  0.3  NaN  NaN  NaN

keys

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

ключи : последовательность, по умолчанию Нет.
Если пройдено несколько уровней, они должны содержать кортежи. Создайте иерархический индекс, используя переданные ключи в качестве самого внешнего уровня

axis=0

При конкатенации Seriesобъектов axis=0(расширении индекса).

Эти ключи становятся новым начальным уровнем MultiIndexобъекта в атрибуте index.

 #           length 3             length 3           #         length 2        length 2
 #          /--------\         /-----------\         #          /----\         /------\
 pd.concat([s1, s2, s3], keys=['A', 'B', 'C'])       pd.concat([s1, s2], keys=['A', 'B'])
----------------------------------------------      -------------------------------------
A  2    1                                           A  2    1
   3    2                                              3    2
B  1    3                                           B  1    3
   2    4                                              2    4
C  1    5                                           dtype: int64
   3    6
dtype: int64

Однако мы можем использовать в keysаргументе не только скалярные значения, чтобы создать еще более глубокое MultiIndex. Здесь мы передаем tuplesдлину 2 и добавляем два новых уровня a MultiIndex:

 pd.concat(
     [s1, s2, s3],
     keys=[('A', 'X'), ('A', 'Y'), ('B', 'X')])
-----------------------------------------------
A  X  2    1
      3    2
   Y  1    3
      2    4
B  X  1    5
      3    6
dtype: int64

axis=1

Немного иначе обстоит дело с удлинением по столбцам. Когда мы использовали axis=0(см. Выше), наши keysдействовали как MultiIndexуровни в дополнение к существующему индексу. Для axis=1, мы имеем в виду ось, котораяSeries которой нет у объектов, а именноcolumns атрибут.

Вариации двух Seriesсaxis=1

Обратите внимание, что присвоение имен s1и s2имеет значение, пока не keysпереданы no , но оно отменяется, если keysони переданы.

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('U'),
 pd.concat(    |      [s1, s2],        |      [s1.rename('U'),  |       s2.rename('V')],
     [s1, s2], |      axis=1,          |       s2.rename('V')], |       axis=1,
     axis=1)   |      keys=['X', 'Y']) |       axis=1)          |       keys=['X', 'Y'])
-------------- | --------------------- | ---------------------- | ----------------------
     0    1    |      X    Y           |      U    V            |      X    Y
1  NaN  3.0    | 1  NaN  3.0           | 1  NaN  3.0            | 1  NaN  3.0
2  1.0  4.0    | 2  1.0  4.0           | 2  1.0  4.0            | 2  1.0  4.0
3  2.0  NaN    | 3  2.0  NaN           | 3  2.0  NaN            | 3  2.0  NaN
MultiIndexс Seriesиaxis=1
 pd.concat(
     [s1, s2],
     axis=1,
     keys=[('W', 'X'), ('W', 'Y')])
-----------------------------------
     W
     X    Y
1  NaN  3.0
2  1.0  4.0
3  2.0  NaN
Два DataFrameсaxis=1

Как и в axis=0примерах, keysдобавьте уровни к MultiIndex, но на этот раз к объекту, хранящемуся в columnsатрибуте.

 pd.concat(                     |  pd.concat(
     [d1, d2],                  |      [d1, d2],
     axis=1,                    |      axis=1,
     keys=['X', 'Y'])           |      keys=[('First', 'X'), ('Second', 'X')])
------------------------------- | --------------------------------------------
     X              Y           |   First           Second
     A    B    C    B    C    D |       X                X
1  NaN  NaN  NaN  0.4  0.5  0.6 |       A    B    C      B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6 | 1   NaN  NaN  NaN    0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN | 2   0.1  0.2  0.3    0.4  0.5  0.6
                                | 3   0.1  0.2  0.3    NaN  NaN  NaN
Seriesи DataFrameсaxis=1

Это сложно. В этом случае значение скалярного ключа не может действовать как единственный уровень индекса для Seriesобъекта, когда он становится столбцом, а также выступать в качестве первого уровня MultiIndexдля DataFrame. Итак, Pandas снова будет использовать nameатрибут Seriesобъекта в качестве источника имени столбца.

 pd.concat(           |  pd.concat(
     [s1, d1],        |      [s1.rename('Z'), d1],
     axis=1,          |      axis=1,
     keys=['X', 'Y']) |      keys=['X', 'Y'])
--------------------- | --------------------------
   X    Y             |    X    Y
   0    A    B    C   |    Z    A    B    C
2  1  0.1  0.2  0.3   | 2  1  0.1  0.2  0.3
3  2  0.1  0.2  0.3   | 3  2  0.1  0.2  0.3
Ограничения keysи MultiIndexвыводы.

Кажется, что Pandas только выводит имена столбцов из Seriesимени, но он не заполняет пробелы при выполнении аналогичной конкатенации между фреймами данных с другим количеством уровней столбцов.

d1_ = pd.concat(
    [d1], axis=1,
    keys=['One'])
d1_

   One
     A    B    C
2  0.1  0.2  0.3
3  0.1  0.2  0.3

Затем объедините это с другим фреймом данных только с одним уровнем в объекте столбцов, и Pandas откажется пытаться создать кортежи MultiIndexобъекта и объединить все фреймы данных, как если бы один уровень объектов, скаляров и кортежей.

pd.concat([d1_, d2], axis=1)

   (One, A)  (One, B)  (One, C)    B    C    D
1       NaN       NaN       NaN  0.4  0.5  0.6
2       0.1       0.2       0.3  0.4  0.5  0.6
3       0.1       0.2       0.3  NaN  NaN  NaN

Передача dictвместоlist

При передаче pandas.concatсловаря в качестве keysпараметра будут использоваться ключи из словаря .

 # axis=0               |  # axis=1
 pd.concat(             |  pd.concat(
     {0: d1, 1: d2})    |      {0: d1, 1: d2}, axis=1)
----------------------- | -------------------------------
       A    B    C    D |      0              1
0 2  0.1  0.2  0.3  NaN |      A    B    C    B    C    D
  3  0.1  0.2  0.3  NaN | 1  NaN  NaN  NaN  0.4  0.5  0.6
1 1  NaN  0.4  0.5  0.6 | 2  0.1  0.2  0.3  0.4  0.5  0.6
  2  NaN  0.4  0.5  0.6 | 3  0.1  0.2  0.3  NaN  NaN  NaN

levels

Это используется в сочетании с keysаргументом. Если levelsоставить значение по умолчанию None, Pandas будет принимать уникальные значения каждого уровня результата MultiIndexи использовать их в качестве объекта, используемого в index.levelsатрибуте результата .

уровни : список последовательностей, по умолчанию нет.
Определенные уровни (уникальные значения) для использования при построении MultiIndex. В противном случае они будут выведены из ключей.

Если Pandas уже делает вывод, какими должны быть эти уровни, какое преимущество указывать это самим? Я покажу один пример и предоставлю вам возможность придумать другие причины, по которым это может быть полезно.

пример

Согласно документации, levelsаргумент - это список последовательностей. Это означает, что мы можем использовать другую pandas.Indexкак одну из этих последовательностей.

Рассмотрим фрейм данных, dfкоторый является объединением d1, d2и d3:

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'])

df

  First           Second           Fourth
      A    B    C      B    C    D      A    B    D
1   NaN  NaN  NaN    0.4  0.5  0.6    0.7  0.8  0.9
2   0.1  0.2  0.3    0.4  0.5  0.6    NaN  NaN  NaN
3   0.1  0.2  0.3    NaN  NaN  NaN    0.7  0.8  0.9

Уровни объекта столбцов:

print(df, *df.columns.levels, sep='\n')

Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')

Если мы используем sumвнутри a, groupbyмы получим:

df.groupby(axis=1, level=0).sum()

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

Но что, если бы вместо ['First', 'Second', 'Fourth']других недостающих категорий с именем Thirdи Fifth? И я хотел, чтобы они были включены в результаты groupbyагрегации? Мы можем это сделать, если бы у нас был pandas.CategoricalIndex. И мы можем уточнить это заранее с levelsаргументом.

Вместо этого давайте определим dfкак:

cats = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
lvl = pd.CategoricalIndex(cats, categories=cats, ordered=True)

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'],
    levels=[lvl]
)

df

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

Но первый уровень объекта столбцов:

df.columns.levels[0]

CategoricalIndex(
    ['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    categories=['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    ordered=True, dtype='category')

И наше groupbyсуммирование выглядит так:

df.groupby(axis=1, level=0).sum()

   First  Second  Third  Fourth  Fifth
1    0.0     1.5    0.0     2.4    0.0
2    0.6     1.5    0.0     0.0    0.0
3    0.6     0.0    0.0     2.4    0.0

names

Это используется для обозначения уровней результата MultiIndex. Длина namesсписка должна соответствовать количеству уровней в результате MultiIndex.

имена : список, по умолчанию Нет
Имена уровней в итоговом иерархическом индексе

 # axis=0                     |  # axis=1
 pd.concat(                   |  pd.concat(
     [d1, d2],                |      [d1, d2],
     keys=[0, 1],             |      axis=1, keys=[0, 1],
     names=['lvl0', 'lvl1'])  |      names=['lvl0', 'lvl1'])
----------------------------- | ----------------------------------
             A    B    C    D | lvl0    0              1
lvl0 lvl1                     | lvl1    A    B    C    B    C    D
0    2     0.1  0.2  0.3  NaN | 1     NaN  NaN  NaN  0.4  0.5  0.6
     3     0.1  0.2  0.3  NaN | 2     0.1  0.2  0.3  0.4  0.5  0.6
1    1     NaN  0.4  0.5  0.6 | 3     0.1  0.2  0.3  NaN  NaN  NaN
     2     NaN  0.4  0.5  0.6 |

verify_integrity

Не требующая пояснений документация

verify_integrity : boolean, по умолчанию False
Проверить, содержит ли новая объединенная ось дубликаты. Это может быть очень дорого по сравнению с фактическим объединением данных.

Поскольку в результате индекс от конкатенации d1и d2не является уникальным, оно не будет проверки целостности.

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

А также

pd.concat([d1, d2], verify_integrity=True)

> ValueError: индексы имеют перекрывающиеся значения: [2]

PiRSquared
источник
23
для сообщества было бы намного полезнее просто сделать запрос на перенос, чтобы добавить несколько недостающих примеров (всего пару) в основную документацию; SO доступен только для поиска, но не для просмотра; здесь было бы полезно разместить ссылку на документы - подавляющее большинство из них уже хорошо и полностью задокументировано
Джефф
6
@Jeff, мой рост был медленным. Использование git - одно из них. Я обещаю, что это то, чем я хочу заняться.
piRSquared
Использование pd.concat(..., levels=[lvl]).groupby(axis=1, level=0).sum()дает другой результат, чем pd.concat(..., levels=[cats]).groupby(axis=1, level=0).sum(). Ты знаешь почему? В документах говорится, что это levelsдолжен быть список последовательностей.
unutbu 03
1
Отличный ответ, но я думаю, что в разделе Passing a dict instead of a listнужен пример с использованием словаря, а не списка.
unutbu 03
1
@unutbu Я исправил dictпример, спасибо. Причина в том, что lvlэто категориальный указатель, а catsне просто список. При группировке по категориальному типу отсутствующие категории заполняются нулями и нулями, где это необходимо. Смотрите это
piRSquared