¿Cómo pivotar un marco de datos?
- ¿Qué es pivote?
- ¿Cómo giro?
- ¿Es esto un pivote?
- ¿Formato largo a formato ancho?
He visto muchas preguntas sobre tablas dinámicas. Incluso si no saben que están preguntando sobre tablas dinámicas, por lo general lo están. Es virtualmente imposible escribir una pregunta canónica y una respuesta que abarque todos los aspectos de pivotar ...
... Pero voy a intentarlo.
El problema con las preguntas y respuestas existentes es que a menudo la pregunta se centra en un matiz que el OP tiene problemas para generalizar para utilizar varias de las 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
- Buena pregunta y respuesta. Pero la respuesta solo responde a la pregunta específica con poca explicación.
- 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.
- Otra pregunta decente, pero la respuesta se centra en un método, a saber pd.DataFrame.pivot
Entonces, cada vez que alguien busca pivot, obtiene resultados esporádicos que probablemente no responderán a su pregunta específica.
Preparar
Puede notar que llamé visiblemente a mis columnas y valores de columna relevantes para que se correspondan con la forma en que voy a girar en las respuestas a continuación.
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)
- ¿Por qué consigo - ValueError: Index contains duplicate entries, cannot reshape
- ¿Cómo giro de - dfmanera que los- colvalores sean columnas, los- rowvalores sean el índice y la media de- val0los 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
- ¿Cómo giro de - dfmanera que los- colvalores sean columnas, los- rowvalores sean el índice, la media de- val0los valores y los valores faltantes- 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
- ¿Puedo conseguir algo más que - meantal vez- 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
- ¿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
- ¿Puedo agregar sobre múltiples 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
- ¿Se puede subdividir por varias 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
- 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
- ¿Puedo agregar la frecuencia con 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
- ¿Cómo convierto un DataFrame de largo a ancho girando SOLO en dos columnas? Dado, - np.random.seed([3, 1415]) df2 = pd.DataFrame({'A': list('aaaabbbc'), 'B': np.random.choice(15, 8)}) df2 A B 0 a 0 1 a 11 2 a 2 3 a 11 4 b 10 5 b 10 6 b 14 7 c 7- Lo esperado debería verse algo así como - a b c 0 0.0 10.0 7.0 1 11.0 10.0 NaN 2 2.0 14.0 NaN 3 11.0 NaN NaN
- ¿Cómo puedo aplanar el índice múltiple a índice único después - pivot- Desde - 1 2 1 1 2 a 2 1 1 b 2 1 0 c 1 0 0- A - 1|1 2|1 2|2 a 2 1 1 b 2 1 0 c 1 0 0
Respuestas
Comenzamos respondiendo la primera pregunta:
Pregunta 1
¿Por qué consigo
ValueError: Index contains duplicate entries, cannot reshape
Esto ocurre porque pandas está intentando volver a indexar un objeto columnsu indexcon entradas duplicadas. Hay varios métodos a utilizar que pueden realizar un pivote. Algunos de ellos no son adecuados para 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 rowy col:
df.duplicated(['row', 'col']).any()
True
Entonces, cuando pivotuso
df.pivot(index='row', columns='col', values='val0')
Recibo el error mencionado anteriormente. De hecho, obtengo el mismo error cuando intento realizar la misma tarea con:
df.set_index(['row', 'col'])['val0'].unstack()
Aquí hay una lista de modismos que podemos usar para pivotar
- pd.DataFrame.groupby+- pd.DataFrame.unstack- Buen enfoque general para realizar casi cualquier tipo de pivote
- Especifique todas las columnas que constituirán los niveles de fila pivotada y los niveles de columna en un grupo por. Lo sigue seleccionando las columnas restantes que desea agregar y las funciones que desea realizar la agregación. Finalmente, tienes unstacklos niveles que quieres que estén en el índice de la columna.
 
- pd.DataFrame.pivot_table- Una versión glorificada de groupbycon una 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 agregaciones.
 
- Una versión glorificada de 
- pd.DataFrame.set_index+- pd.DataFrame.unstack- Conveniente e intuitivo para algunos (incluido yo mismo). No se pueden manejar claves agrupadas duplicadas.
- De manera similar al groupbyparadigma, especificamos todas las columnas que eventualmente serán niveles de fila o columna y las establecemos como índice. Seguimosunstacklos niveles que queramos en las columnas. Si los niveles de índice o de columna restantes no son únicos, este método fallará.
 
- pd.DataFrame.pivot- Muy similar a set_indexque comparte la limitación de clave duplicada. La API también es muy limitada. Sólo toma valores escalares paraindex,columns,values.
- Similar al pivot_tablemétodo 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á.
 
- Muy similar a 
- pd.crosstab- Esta es una versión especializada pivot_tabley en su forma más pura es la forma más intuitiva de realizar varias tareas.
 
- Esta es una versión especializada 
- 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 se sienta cómodo usándolo, obtendrá las recompensas de rendimiento.
 
- pd.get_dummies+- pd.DataFrame.dot- Lo uso para realizar tabulaciones cruzadas de forma inteligente.
 
Ejemplos
Lo que voy a hacer para cada respuesta y pregunta subsiguientes es responder usando pd.DataFrame.pivot_table. Luego te brindaré alternativas para realizar la misma tarea.  
Pregunta 3
¿Cómo giro de
dfmanera que loscolvalores sean columnas, losrowvalores sean el índice, la media deval0los valores y los valores faltantes0?
- pd.DataFrame.pivot_table- fill_valueno está configurado de forma predeterminada. Tiendo a configurarlo apropiadamente. En este caso lo configuré en- 0. Observe que me salté la pregunta 2 porque es la misma que esta respuesta sin la- fill_value
- aggfunc='mean'es el 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 conseguir algo más que
meantal vezsum?
- 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_tabley crosstabyo tenía que pasar la lista de llamadas. Por otro lado, groupby.agges capaz de tomar cadenas para un número limitado de funciones especiales.  groupby.aggtambién habría tomado los mismos invocables que pasamos a los demás, pero a menudo es más eficiente aprovechar los nombres de las funciones de cadena ya que hay eficiencias que se pueden obtener.
- 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 sobre múltiples columnas de valor?
- pd.DataFrame.pivot_tablepasamos- values=['val0', 'val1']pero podríamos haber dejado eso completamente- 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 varias 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 varias 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_indexporque 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 con 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.crosstab- 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
Pregunta 10
¿Cómo convierto un DataFrame de largo a ancho girando SOLO en dos columnas?
El primer paso es asignar un número a cada fila; este número será el índice de fila de ese valor en el resultado pivotado. Esto se hace usando GroupBy.cumcount:
df2.insert(0, 'count', df.groupby('A').cumcount())
df2
   count  A   B
0      0  a   0
1      1  a  11
2      2  a   2
3      3  a  11
4      0  b  10
5      1  b  10
6      2  b  14
7      0  c   7
El segundo paso es utilizar la columna recién creada como índice para llamar DataFrame.pivot.
df2.pivot(*df)
# df.pivot(index='count', columns='A', values='B')
A         a     b    c
count                 
0       0.0  10.0  7.0
1      11.0  10.0  NaN
2       2.0  14.0  NaN
3      11.0   NaN  NaN
Pregunta 11
¿Cómo puedo aplanar el índice múltiple a índice único después
pivot
Si columnsescribe objectcon cadenajoin 
df.columns = df.columns.map('|'.join)
más format
df.columns = df.columns.map('{0[0]}|{0[1]}'.format) 
Para extender la respuesta de @ piRSquared, otra versión de la Pregunta 10
Pregunta 10.1
Marco de datos:
d = data = {'A': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 5},
 'B': {0: 'a', 1: 'b', 2: 'c', 3: 'a', 4: 'b', 5: 'a', 6: 'c'}}
df = pd.DataFrame(d)
   A  B
0  1  a
1  1  b
2  1  c
3  2  a
4  2  b
5  3  a
6  5  c
Salida:
   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None
Usando df.groupbyypd.Series.tolist
t = df.groupby('A')['B'].apply(list)
out = pd.DataFrame(t.tolist(),index=t.index)
out
   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None
O una alternativa mucho mejor usando pd.pivot_tablecondf.squeeze.
t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)