Cómo hacer pivotar un dataframe

  • ¿Qué es pivote?
  • ¿Cómo puedo pivotar?
  • ¿Es este un pivote?
  • Formato largo a formato ancho?

He visto muchas preguntas que preguntan sobre tablas dinámicas. Incluso si no saben que están preguntando acerca de las tablas dinámicas, por lo general lo son. Es virtualmente imposible escribir una pregunta y respuesta canónicas que abarque todos los aspectos de la rotación …

… Pero voy a darle una oportunidad.


El problema con las preguntas y respuestas existentes es que a menudo la pregunta se enfoca en un matiz que el OP tiene problemas para generalizar con el fin de utilizar una serie de buenas respuestas existentes. Sin embargo, ninguna de las respuestas intenta dar una explicación completa (porque es una tarea desalentadora)

Mira algunos ejemplos de mi búsqueda de google

  1. ¿Cómo hacer pivotar un dataframe en Pandas?
    • Buena pregunta y respuesta. Pero la respuesta solo responde a la pregunta específica con poca explicación.
  2. pandas pivotan tabla a dataframe
    • En esta pregunta, el OP se ocupa de la salida del pivote. Es decir, cómo se ven las columnas. OP quería que se pareciera a R. Esto no es muy útil para los usuarios de pandas.
  3. pandas girando un dataframe, filas duplicadas
    • Otra pregunta decente, pero la respuesta se centra en un método, a saber, pd.DataFrame.pivot

Entonces, cuando alguien busca un pivot , obtiene resultados esporádicos que probablemente no responderán a su pregunta específica.


Preparar

Puede notar que nombré mis columnas y valores de columna relevantes para corresponder con cómo voy a pivotar en las respuestas a continuación. Preste atención para familiarizarse con el nombre de los nombres de las columnas donde se obtienen los resultados que está buscando.

 import numpy as np import pandas as pd from numpy.core.defchararray import add np.random.seed([3,1415]) n = 20 cols = np.array(['key', 'row', 'item', 'col']) arr1 = (np.random.randint(5, size=(n, 4)) // [2, 1, 2, 1]).astype(str) df = pd.DataFrame( add(cols, arr1), columns=cols ).join( pd.DataFrame(np.random.rand(n, 2).round(2)).add_prefix('val') ) print(df) key row item col val0 val1 0 key0 row3 item1 col3 0.81 0.04 1 key1 row2 item1 col2 0.44 0.07 2 key1 row0 item1 col0 0.77 0.01 3 key0 row4 item0 col2 0.15 0.59 4 key1 row0 item2 col1 0.81 0.64 5 key1 row2 item2 col4 0.13 0.88 6 key2 row4 item1 col3 0.88 0.39 7 key1 row4 item1 col1 0.10 0.07 8 key1 row0 item2 col4 0.65 0.02 9 key1 row2 item0 col2 0.35 0.61 10 key2 row0 item2 col1 0.40 0.85 11 key2 row4 item1 col2 0.64 0.25 12 key0 row2 item2 col3 0.50 0.44 13 key0 row4 item1 col4 0.24 0.46 14 key1 row3 item2 col3 0.28 0.11 15 key0 row3 item1 col1 0.31 0.23 16 key0 row0 item2 col3 0.86 0.01 17 key0 row4 item0 col3 0.64 0.21 18 key2 row2 item2 col0 0.13 0.45 19 key0 row2 item0 col4 0.37 0.70 

Pregunta (s)

  1. ¿Por qué obtengo ValueError: Index contains duplicate entries, cannot reshape

  2. ¿Cómo hago pivotar df para que los valores de col sean columnas, los valores de row sean el índice y la media de val0 sean los valores?

     col col0 col1 col2 col3 col4 row row0 0.77 0.605 NaN 0.860 0.65 row2 0.13 NaN 0.395 0.500 0.25 row3 NaN 0.310 NaN 0.545 NaN row4 NaN 0.100 0.395 0.760 0.24 
  3. ¿Cómo hago pivotar df para que los valores de col sean columnas, los valores de row sean el índice, la media de val0 sean los valores y los valores faltantes sean 0 ?

     col col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.100 0.395 0.760 0.24 
  4. ¿Puedo obtener algo que no sea mean , como tal vez la sum ?

     col col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 row2 0.13 0.00 0.79 0.50 0.50 row3 0.00 0.31 0.00 1.09 0.00 row4 0.00 0.10 0.79 1.52 0.24 
  5. ¿Puedo hacer más de una agregación a la vez?

      sum mean col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.00 0.79 0.50 0.50 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.31 0.00 1.09 0.00 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.10 0.79 1.52 0.24 0.00 0.100 0.395 0.760 0.24 
  6. ¿Puedo agregar en varias columnas de valor?

      val0 val1 col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 0.01 0.745 0.00 0.010 0.02 row2 0.13 0.000 0.395 0.500 0.25 0.45 0.000 0.34 0.440 0.79 row3 0.00 0.310 0.000 0.545 0.00 0.00 0.230 0.00 0.075 0.00 row4 0.00 0.100 0.395 0.760 0.24 0.00 0.070 0.42 0.300 0.46 
  7. ¿Se puede subdividir por múltiples columnas?

     item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 row row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.605 0.86 0.65 row2 0.35 0.00 0.37 0.00 0.00 0.44 0.00 0.00 0.13 0.000 0.50 0.13 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.000 0.28 0.00 row4 0.15 0.64 0.00 0.00 0.10 0.64 0.88 0.24 0.00 0.000 0.00 0.00 
  8. O

     item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 key row key0 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.86 0.00 row2 0.00 0.00 0.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.50 0.00 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.00 0.00 0.00 row4 0.15 0.64 0.00 0.00 0.00 0.00 0.00 0.24 0.00 0.00 0.00 0.00 key1 row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.81 0.00 0.65 row2 0.35 0.00 0.00 0.00 0.00 0.44 0.00 0.00 0.00 0.00 0.00 0.13 row3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.28 0.00 row4 0.00 0.00 0.00 0.00 0.10 0.00 0.00 0.00 0.00 0.00 0.00 0.00 key2 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.40 0.00 0.00 row2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.13 0.00 0.00 0.00 row4 0.00 0.00 0.00 0.00 0.00 0.64 0.88 0.00 0.00 0.00 0.00 0.00 
  9. ¿Puedo agregar la frecuencia en la que la columna y las filas aparecen juntas, también conocida como “tabulación cruzada”?

     col col0 col1 col2 col3 col4 row row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1 

Comenzamos contestando la primera pregunta:

Pregunta 1

¿Por qué obtengo ValueError: Index contains duplicate entries, cannot reshape

Esto ocurre porque pandas está intentando reindexar una columns o un objeto de index con entradas duplicadas. Existen varios métodos para usar que pueden realizar un pivote. Algunos de ellos no son adecuados cuando hay duplicados de las claves en las que se le pide que gire. Por ejemplo. Considere pd.DataFrame.pivot . Sé que hay entradas duplicadas que comparten los valores de row y col :

 df.duplicated(['row', 'col']).any() True 

Así que cuando pivot usando

 df.pivot(index='row', columns='col', values='val0') 

Me sale el error mencionado anteriormente. De hecho, recibo el mismo error cuando bash realizar la misma tarea con:

 df.set_index(['row', 'col'])['val0'].unstack() 

Aquí hay una lista de expresiones idiomáticas que podemos usar para pivotar.

  1. pd.DataFrame.groupby + pd.DataFrame.unstack
    • Buen enfoque general para hacer casi cualquier tipo de pivote
    • Especifica todas las columnas que constituirán los niveles de fila pivotados y los niveles de columna en un grupo por. A continuación, selecciona las columnas restantes que desea agregar y las funciones que desea que realicen la agregación. Finalmente, unstack los niveles que deseas que estén en el índice de la columna.
  2. pd.DataFrame.pivot_table
    • Una versión glorificada de groupby con API más intuitiva. Para muchas personas, este es el enfoque preferido. Y es el enfoque previsto por los desarrolladores.
    • Especifique el nivel de fila, los niveles de columna, los valores que se agregarán y las funciones para realizar las agregaciones.
  3. pd.DataFrame.set_index + pd.DataFrame.unstack
    • Conveniente e intuitivo para algunos (yo incluido). No se pueden manejar claves duplicadas agrupadas.
    • De manera similar al paradigma groupby , especificamos todas las columnas que eventualmente serán niveles de fila o columna y las configuramos para que sean el índice. Luego unstack los niveles que queremos en las columnas. Si los niveles de índice o los niveles de columna restantes no son únicos, este método fallará.
  4. pd.DataFrame.pivot
    • Muy similar a set_index en que comparte la limitación de la clave duplicada. La API es muy limitada también. Solo toma valores escalares para el index , columns , values .
    • Similar al método pivot_table en que seleccionamos filas, columnas y valores sobre los cuales pivotar. Sin embargo, no podemos agregar y si las filas o columnas no son únicas, este método fallará.
  5. pd.crosstab
    • Esta es una versión especializada de pivot_table y en su forma más pura es la forma más intuitiva de realizar varias tareas.
  6. pd.factorize + np.bincount
    • Esta es una técnica muy avanzada que es muy oscura pero muy rápida. No se puede usar en todas las circunstancias, pero cuando se pueda usar y usted se sienta cómodo usándolo, cosechará las recompensas de rendimiento.
  7. pd.get_dummies + pd.DataFrame.dot
    • Utilizo esto para realizar inteligentemente la tabulación cruzada.

Ejemplos

Lo que voy a hacer para cada respuesta y pregunta subsiguiente es responderla utilizando pd.DataFrame.pivot_table . Luego te proporcionaré alternativas para realizar la misma tarea.

Pregunta 3

¿Cómo hago pivotar df para que los valores de col sean columnas, los valores de row sean el índice, la media de val0 sean los valores y los valores faltantes sean 0 ?

  • pd.DataFrame.pivot_table

    • fill_value no se establece de forma predeterminada. Tiendo a configurarlo adecuadamente. En este caso lo puse a 0 . Note que salté la pregunta 2 ya que es la misma que esta respuesta sin el fill_value
    • aggfunc='mean' es el valor predeterminado y no tuve que configurarlo. Lo incluí para ser explícito.

       df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc='mean') col col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 row2 0.13 0.000 0.395 0.500 0.25 row3 0.00 0.310 0.000 0.545 0.00 row4 0.00 0.100 0.395 0.760 0.24 
  • pd.DataFrame.groupby

     df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0) 
  • pd.crosstab

     pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='mean').fillna(0) 

Pregunta 4

¿Puedo obtener algo que no sea mean , como tal vez la sum ?

  • pd.DataFrame.pivot_table

     df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc='sum') col col0 col1 col2 col3 col4 row row0 0.77 1.21 0.00 0.86 0.65 row2 0.13 0.00 0.79 0.50 0.50 row3 0.00 0.31 0.00 1.09 0.00 row4 0.00 0.10 0.79 1.52 0.24 
  • pd.DataFrame.groupby

     df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0) 
  • pd.crosstab

     pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc='sum').fillna(0) 

Pregunta 5

¿Puedo hacer más de una agregación a la vez?

Tenga en cuenta que para pivot_table y cross_tab necesitaba pasar una lista de callables. Por otra parte, groupby.agg puede tomar cadenas para un número limitado de funciones especiales. groupby.agg también habría tomado los mismos callables que pasamos a los demás, pero a menudo es más eficiente aprovechar los nombres de función de cadena, ya que hay eficiencias que ganar.

  • pd.DataFrame.pivot_table

     df.pivot_table( values='val0', index='row', columns='col', fill_value=0, aggfunc=[np.size, np.mean]) size mean col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 1 2 0 1 1 0.77 0.605 0.000 0.860 0.65 row2 1 0 2 1 2 0.13 0.000 0.395 0.500 0.25 row3 0 1 0 2 0 0.00 0.310 0.000 0.545 0.00 row4 0 1 2 2 1 0.00 0.100 0.395 0.760 0.24 
  • pd.DataFrame.groupby

     df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0) 
  • pd.crosstab

     pd.crosstab( index=df['row'], columns=df['col'], values=df['val0'], aggfunc=[np.size, np.mean]).fillna(0, downcast='infer') 

Pregunta 6

¿Puedo agregar en varias columnas de valor?

  • pd.DataFrame.pivot_table pasamos values=['val0', 'val1'] pero podríamos haberlo values=['val0', 'val1'] por completo

     df.pivot_table( values=['val0', 'val1'], index='row', columns='col', fill_value=0, aggfunc='mean') val0 val1 col col0 col1 col2 col3 col4 col0 col1 col2 col3 col4 row row0 0.77 0.605 0.000 0.860 0.65 0.01 0.745 0.00 0.010 0.02 row2 0.13 0.000 0.395 0.500 0.25 0.45 0.000 0.34 0.440 0.79 row3 0.00 0.310 0.000 0.545 0.00 0.00 0.230 0.00 0.075 0.00 row4 0.00 0.100 0.395 0.760 0.24 0.00 0.070 0.42 0.300 0.46 
  • pd.DataFrame.groupby

     df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0) 

Pregunta 7

¿Se puede subdividir por múltiples columnas?

  • pd.DataFrame.pivot_table

     df.pivot_table( values='val0', index='row', columns=['item', 'col'], fill_value=0, aggfunc='mean') item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 row row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.605 0.86 0.65 row2 0.35 0.00 0.37 0.00 0.00 0.44 0.00 0.00 0.13 0.000 0.50 0.13 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.000 0.28 0.00 row4 0.15 0.64 0.00 0.00 0.10 0.64 0.88 0.24 0.00 0.000 0.00 0.00 
  • pd.DataFrame.groupby

     df.groupby( ['row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1) 

Pregunta 8

¿Se puede subdividir por múltiples columnas?

  • pd.DataFrame.pivot_table

     df.pivot_table( values='val0', index=['key', 'row'], columns=['item', 'col'], fill_value=0, aggfunc='mean') item item0 item1 item2 col col2 col3 col4 col0 col1 col2 col3 col4 col0 col1 col3 col4 key row key0 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.86 0.00 row2 0.00 0.00 0.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.50 0.00 row3 0.00 0.00 0.00 0.00 0.31 0.00 0.81 0.00 0.00 0.00 0.00 0.00 row4 0.15 0.64 0.00 0.00 0.00 0.00 0.00 0.24 0.00 0.00 0.00 0.00 key1 row0 0.00 0.00 0.00 0.77 0.00 0.00 0.00 0.00 0.00 0.81 0.00 0.65 row2 0.35 0.00 0.00 0.00 0.00 0.44 0.00 0.00 0.00 0.00 0.00 0.13 row3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.28 0.00 row4 0.00 0.00 0.00 0.00 0.10 0.00 0.00 0.00 0.00 0.00 0.00 0.00 key2 row0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.40 0.00 0.00 row2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.13 0.00 0.00 0.00 row4 0.00 0.00 0.00 0.00 0.00 0.64 0.88 0.00 0.00 0.00 0.00 0.00 
  • pd.DataFrame.groupby

     df.groupby( ['key', 'row', 'item', 'col'] )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1) 
  • pd.DataFrame.set_index porque el conjunto de claves es único tanto para filas como para columnas

     df.set_index( ['key', 'row', 'item', 'col'] )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1) 

Pregunta 9

¿Puedo agregar la frecuencia en la que la columna y las filas aparecen juntas, también conocida como “tabulación cruzada”?

  • pd.DataFrame.pivot_table

     df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size') col col0 col1 col2 col3 col4 row row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1 
  • pd.DataFrame.groupby

     df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0) 
  • pd.cross_tab

     pd.crosstab(df['row'], df['col']) 
  • pd.factorize + np.bincount

     # get integer factorization `i` and unique values `r` # for column `'row'` i, r = pd.factorize(df['row'].values) # get integer factorization `j` and unique values `c` # for column `'col'` j, c = pd.factorize(df['col'].values) # `n` will be the number of rows # `m` will be the number of columns n, m = r.size, c.size # `i * m + j` is a clever way of counting the # factorization bins assuming a flat array of length # `n * m`. Which is why we subsequently reshape as `(n, m)` b = np.bincount(i * m + j, minlength=n * m).reshape(n, m) # BTW, whenever I read this, I think 'Bean, Rice, and Cheese' pd.DataFrame(b, r, c) col3 col2 col0 col1 col4 row3 2 0 0 1 0 row2 1 2 1 0 2 row0 1 0 1 2 1 row4 2 2 0 1 1 
  • pd.get_dummies

     pd.get_dummies(df['row']).T.dot(pd.get_dummies(df['col'])) col0 col1 col2 col3 col4 row0 1 2 0 1 1 row2 1 0 2 1 2 row3 0 1 0 2 0 row4 0 1 2 2 1