¿Cuáles son los argumentos de 'niveles', 'claves' y nombres en la función concat de Pandas?

94

Preguntas

  • ¿Cómo lo uso pd.concat?
  • ¿Para qué es el levelsargumento?
  • ¿Para qué es el keysargumento?
  • ¿Hay un montón de ejemplos que ayuden a explicar cómo usar todos los argumentos?

La concatfunción de Pandas es la navaja suiza de las utilidades fusionadas. La variedad de situaciones en las que resulta útil son numerosas. La documentación existente omite algunos detalles sobre algunos de los argumentos opcionales. Entre ellos se encuentran los argumentos levelsy keys. Me propuse averiguar qué hacen esos argumentos.

Plantearé una pregunta que actuará como puerta de entrada a muchos aspectos de pd.concat.

Considere las tramas de datos d1, d2y 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])

Si tuviera que concatenar estos junto con

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

Obtengo el resultado esperado con un pandas.MultiIndexpara mi columnsobjeto:

        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

Sin embargo, quería usar la levelsdocumentación del argumento :

niveles : lista de secuencias, por defecto Ninguno. Niveles específicos (valores únicos) para usar para construir un MultiIndex. De lo contrario, se deducirán de las claves.

Así que pasé

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

Y conseguir un KeyError

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

Esto tenía sentido. Los niveles que pasé fueron inadecuados para describir los niveles necesarios indicados por las teclas. Si no hubiera pasado nada, como hice anteriormente, se infieren los niveles (como se indica en la documentación). Pero, ¿de qué otra manera puedo usar este argumento para obtener mejores resultados?

Si intenté esto en su lugar:

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

Yo y obtuve los mismos resultados que los anteriores. Pero cuando agrego un valor más a los niveles,

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

Termino con el mismo marco de datos en apariencia, pero el resultado MultiIndextiene un nivel sin usar.

df.index.levels[0]

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

Entonces, ¿cuál es el punto del levelargumento y debería usarlo de manera keysdiferente?

Estoy usando Python 3.6 y Pandas 0.22.

piRSquared
fuente

Respuestas:

124

En el proceso de responder a esta pregunta por mí mismo, aprendí muchas cosas y quería armar un catálogo de ejemplos y alguna explicación.

La respuesta específica al punto del levelsargumento llegará hacia el final.

pandas.concat: El manual perdido

Enlace a la documentación actual

Importaciones y definición de objetos

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])

Argumentos

objs

El primer argumento con el que nos encontramos es objs:

objs : una secuencia o mapeo de objetos Series, DataFrame o Panel. Si se pasa un dict, las claves ordenadas se utilizarán como argumento de claves, a menos que se pase, en cuyo caso se seleccionarán los valores (ver más abajo). Cualquier objeto None se eliminará silenciosamente a menos que todos sean None, en cuyo caso se generará un ValueError

  • Normalmente vemos esto usado con una lista de objetos Seriesu DataFrame.
  • Les mostraré que también dictpuede ser muy útil.
  • También se pueden usar generadores y pueden ser útiles cuando se usan mapcomo enmap(f, list_of_df)

Por ahora, nos quedaremos con una lista de algunos de los objetos DataFramey Seriesdefinidos anteriormente. Más MultiIndexadelante , mostraré cómo se pueden aprovechar los diccionarios para obtener resultados muy útiles .

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

El segundo argumento que encontramos es axiscuyo valor predeterminado es 0:

eje : {0 / 'índice', 1 / 'columnas'}, predeterminado 0 El eje para concatenar.

Dos DataFrames con axis=0(apilados)

Para valores de 0o indexqueremos decir: "Alinear a lo largo de las columnas y agregar al índice".

Como se muestra arriba, donde usamos axis=0, porque 0es el valor predeterminado, y vemos que el índice de d2extiende el índice de a d1pesar de que haya una superposición del valor 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

Dos DataFrames con axis=1(lado a lado)

Para valores 1o columnsqueremos decir: "Alinear a lo largo del índice y agregar a las columnas",

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

Podemos ver que el índice resultante es la unión de índices y las columnas resultantes son la extensión de las columnas de d1por las columnas de d2.

Dos (o tres) Seriescon axis=0(apilados)

Al combinar a lo pandas.Serieslargo axis=0, obtenemos a pandas.Series. El nombre del resultado Seriesserá a Nonemenos que todos los que Seriesse combinen tengan el mismo nombre. Preste atención a 'Name: A'cuando imprimimos el resultado Series. Cuando no está presente, podemos asumir que el Seriesnombre lo es 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

Dos (o tres) Seriescon axis=1(lado a lado)

Cuando se combina pandas.Seriesa lo largo de axis=1, es el nameatributo que nos referimos a fin de inferir un nombre de columna en el resultante 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

Mixto Seriesy DataFramecon axis=0(apilado)

Al realizar una concatenación de a Seriesy a lo DataFramelargo axis=0, convertimos todo Seriesen una sola columna DataFrames.

Tenga especial en cuenta que se trata de una concatenación axis=0; eso significa extender el índice (filas) mientras alinea las columnas. En los ejemplos siguientes, vemos que el índice se convierte en [2, 3, 2, 3]una adición indiscriminada de índices. Las columnas no se superponen a menos que fuerce el nombre de la Seriescolumna con el argumento para 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

Puede ver que los resultados pd.concat([s1, d1])son los mismos que si lo hubiera realizado to_frameyo mismo.

Sin embargo, puedo controlar el nombre de la columna resultante con un parámetro para to_frame. Cambiar el nombre de Seriescon el renamemétodo no controla el nombre de la columna en el resultado 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

Mixto Seriesy DataFramecon axis=1(lado a lado)

Esto es bastante intuitivo. SeriesEl nombre de columna tiene como valor predeterminado una enumeración de dichos Seriesobjetos cuando un nameatributo no está disponible.

                    |  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

El tercer argumento es joinque describe si la combinación resultante debe ser una combinación externa (predeterminada) o una combinación interna.

join : {'interno', 'externo'}, predeterminado 'externo'
Cómo manejar índices en otros ejes.

Resulta, no hay es lefto rightopción, ya que pd.concatpuede manejar más de sólo dos objetos de fusionarse.

En el caso de d1y d2, las opciones se ven así:

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

El cuarto argumento es lo que nos permite leftfusionarnos y más.

join_axes : lista de objetos de índice
Índices específicos para usar para los otros n - 1 ejes en lugar de realizar la lógica de conjunto interno / externo.

Fusionar a la izquierda

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

Fusionar a la derecha

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 : booleano, predeterminado False
Si es verdadero, no utilice los valores de índice a lo largo del eje de concatenación. El eje resultante se etiquetará como 0, ..., n - 1. Esto es útil si está concatenando objetos donde el eje de concatenación no tiene información de indexación significativa. Tenga en cuenta que los valores de índice en los otros ejes aún se respetan en la combinación.

Como cuando apilo d1encima d2, si no me importan los valores del índice, podría restablecerlos o ignorarlos.

                      |  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

Y al usar 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

Podemos pasar una lista de valores escalares o tuplas para asignar valores de tupla o escalares al MultiIndex correspondiente. La longitud de la lista pasada debe ser la misma que la cantidad de elementos que se concatenan.

claves : secuencia, predeterminado Ninguno
Si se pasan varios niveles, debe contener tuplas. Construya un índice jerárquico usando las claves pasadas como el nivel más externo

axis=0

Al concatenar Seriesobjetos a lo largo axis=0(ampliar el índice).

Esas claves se convierten en un nuevo nivel inicial de un MultiIndexobjeto en el atributo de índice.

 #           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

Sin embargo, podemos usar más que valores escalares en el keysargumento para crear un MultiIndex. Aquí pasamos tuplesde longitud 2 anteponer dos nuevos niveles de 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

Es un poco diferente cuando se extiende a lo largo de columnas. Cuando usamos axis=0(ver arriba) nuestro keysactuaba como MultiIndexniveles además del índice existente. Porque axis=1nos referimos a un eje que los Seriesobjetos no tienen, a saber, el columnsatributo.

Las variaciones de dos Serieswtihaxis=1

Observe que nombrar s1y es s2importante siempre que no keysse pasen, pero se anula si keysse pasan.

               |                       |                        |  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
MultiIndexcon Seriesyaxis=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
Dos DataFrameconaxis=1

Al igual que con los axis=0ejemplos, keysagregue niveles a a MultiIndex, pero esta vez al objeto almacenado en el columnsatributo.

 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
Seriesy DataFrameconaxis=1

Esto es complicado. En este caso, un valor de clave escalar no puede actuar como el único nivel de índice para el Seriesobjeto cuando se convierte en una columna y también actúa como el primer nivel de a MultiIndexpara DataFrame. Entonces, Pandas usará nuevamente el nameatributo del Seriesobjeto como fuente del nombre de la columna.

 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
Limitaciones keyse MultiIndexinferencias.

Pandas solo parece inferir los nombres de las columnas a partir del Seriesnombre, pero no completará los espacios en blanco cuando se haga una concatenación análoga entre marcos de datos con un número diferente de niveles de columna.

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

Luego, concatene esto con otro marco de datos con un solo nivel en el objeto de columnas y Pandas se negará a intentar hacer tuplas del MultiIndexobjeto y combinará todos los marcos de datos como si fueran un solo nivel de objetos, escalares y tuplas.

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

Pasando un en dictlugar de unlist

Al pasar un diccionario, pandas.concatutilizará las claves del diccionario como keysparámetro.

 # 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

Esto se usa junto con el keysargumento. Cuando levelsse deja como su valor predeterminado de None, Pandas tomará los valores únicos de cada nivel del resultado MultiIndexy lo usará como el objeto usado en el index.levelsatributo resultante .

niveles : lista de secuencias, por defecto Ninguno
Niveles específicos (valores únicos) para usar para construir un MultiIndex. De lo contrario, se deducirán de las claves.

Si Pandas ya infiere cuáles deberían ser estos niveles, ¿qué ventaja hay en especificarlo nosotros mismos? Le mostraré un ejemplo y dejaré que usted piense en otras razones por las que esto podría ser útil.

Ejemplo

Según la documentación, el levelsargumento es una lista de secuencias. Esto significa que podemos usar otro pandas.Indexcomo una de esas secuencias.

Considere la trama de datos dfque es la concatenación de d1, d2y 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

Los niveles del objeto columnas son:

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

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

Si usamos sumdentro de un groupbyobtenemos:

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

Pero, ¿y si en lugar de ['First', 'Second', 'Fourth']hubiera otras categorías faltantes nombradasThird y Fifth? ¿Y quería que se incluyeran en los resultados de una groupbyagregación? Podemos hacer esto si tuviéramos un pandas.CategoricalIndex. Y podemos especificar eso de antemano con el levelsargumento.

Entonces, en cambio, definamos df como:

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

Pero el primer nivel del objeto de columnas es:

df.columns.levels[0]

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

Y nuestro groupbyresumen se ve así:

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

Se utiliza para nombrar los niveles de un resultado MultiIndex. La longitud delnames lista debe coincidir con el número de niveles del archivo MultiIndex.

nombres : lista, por defecto Ninguno
Nombres para los niveles en el índice jerárquico resultante

 # 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

Documentación autoexplicativa

verify_integrity : booleano, predeterminado Falso
Compruebe si el nuevo eje concatenado contiene duplicados. Esto puede resultar muy caro en relación con la concatenación de datos real.

Debido a que el índice resultante de la concatenación d1y d2no es único, fallaría la verificación de integridad.

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

Y

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

> ValueError: los índices tienen valores superpuestos: [2]

piRSquared
fuente
23
Realmente sería mucho más útil para la comunidad simplemente hacer una solicitud de extracción para agregar algunos ejemplos faltantes (solo un par) a los documentos principales; SO solo se puede buscar y no se puede navegar; agregar un enlace a los documentos sería útil aquí - la gran mayoría de esto ya está bien y completamente documentado
Jeff
6
@Jeff, hay dimensiones de mi crecimiento que han sido lentas. Usar git es uno de ellos. Prometo que es lo que quiero empezar a hacer.
piRSquared
El uso pd.concat(..., levels=[lvl]).groupby(axis=1, level=0).sum()produce un resultado diferente al pd.concat(..., levels=[cats]).groupby(axis=1, level=0).sum(). ¿Sabes por qué? Los documentos solo dicen que levelsdebería haber una lista de secuencias.
unutbu
1
Gran respuesta, pero creo que la sección sobre Passing a dict instead of a listnecesita un ejemplo usando un dictado, no una lista.
unutbu
1
@unutbu He arreglado el dictejemplo, gracias. La razón es que lvles un índice categórico y catses solo una lista. Al agrupar por tipo categórico, las categorías que faltan se completan con ceros y nulos cuando corresponde. Vea esto
piRSquared