Pivot y Melt¶
Dentro del mundo de los dataframe (o datos tabulares) existen dos formas de presentar la naturaleza de los datos: formato wide y formato long.
Por ejemplo, el conjunto de datos Zoo Data Set presenta las características de diversos animales, de los cuales presentamos las primeras 5 columnas.
| animal_name | hair | feathers | eggs | milk |
|---|---|---|---|---|
| antelope | 1 | 0 | 0 | 1 |
| bear | 1 | 0 | 0 | 1 |
| buffalo | 1 | 0 | 0 | 1 |
| catfish | 0 | 0 | 1 | 0 |
La tabla así presentada se encuentra en wide format, es decir, donde los valores se extienden a través de las columnas.
Sería posible representar el mismo contenido anterior en long format, es decir, donde los mismos valores se indicaran a través de las filas:
|animal_name|characteristic|value| |-----------|----|--------| |antelope|hair |1| |antelope|feathers|0| |antelope|eggs|0| |antelope|milk|1| |...|...|...|...|..| |catfish|hair |0| |catfish|feathers|0| |catfish|eggs|1| |catfish|milk|0|

En python, existen maneras de pasar del formato wide al formato long y viceversa.
Formato long a wide¶
El pivoteo de una tabla corresponde al paso de una tabla desde el formato long al formato wide. Típicamente esto se realiza para poder comparar los valores que se obtienen para algún registro en particular, o para utilizar algunas herramientas de visualización básica que requieren dicho formato.
En Pandas se utiliza los comandos pivot y pivot_table.
pivot¶
La función pivot se utiliza para transformar los datos de formato largo a formato ancho en función de los valores únicos en una columna determinada. Esta función toma tres argumentos: index, columns, y values.
indexse utiliza para especificar la(s) columna(s) que se utilizarán como el índice en el DataFrame resultantecolumnsse utiliza para especificar la columna que se utilizará como las columnas en el DataFrame resultantevaluesse utiliza para especificar la columna que se utilizará como los valores para completar el DataFrame resultante.
Supongamos que tenemos un conjunto de datos que contiene información sobre las ventas de una empresa, con las siguientes columnas: "Fecha", "Vendedor", "Producto" y "Ventas".
import pandas as pd
datos = {
'Fecha': ['2022-01-01', '2022-01-01', '2022-01-02', '2022-01-02', '2022-01-03', '2022-01-03'],
'Vendedor': ['Juan', 'Pedro', 'Juan', 'Pedro', 'Juan', 'Pedro'],
'Producto': ['A', 'B', 'A', 'B', 'A', 'B'],
'Ventas': [100, 200, 150, 250, 120, 180]
}
df = pd.DataFrame(datos)
1.- Pivot simple: si queremos ver las ventas totales por vendedor y por fecha, podemos hacer lo siguiente:
pivot_df = df.pivot(index='Fecha', columns='Vendedor', values='Ventas')
pivot_df
| Vendedor | Juan | Pedro |
|---|---|---|
| Fecha | ||
| 2022-01-01 | 100 | 200 |
| 2022-01-02 | 150 | 250 |
| 2022-01-03 | 120 | 180 |
2.- Pivot múltiple: si queremos ver las ventas totales por vendedor y por fecha, y además queremos desglosar las ventas por producto, podemos hacer lo siguiente:
pivot_df = df.pivot(index=['Fecha', 'Producto'], columns='Vendedor', values='Ventas')
pivot_df
| Vendedor | Juan | Pedro | |
|---|---|---|---|
| Fecha | Producto | ||
| 2022-01-01 | A | 100.0 | NaN |
| B | NaN | 200.0 | |
| 2022-01-02 | A | 150.0 | NaN |
| B | NaN | 250.0 | |
| 2022-01-03 | A | 120.0 | NaN |
| B | NaN | 180.0 |
pivot_table¶
La función pivot_table también se utiliza para transformar los datos de formato largo a formato ancho, pero con la capacidad adicional de realizar operaciones de agregación en los valores correspondientes a cada combinación de valores de índice y columna. Esta función toma muchos argumentos, pero los más importantes son: index, columns, y values como en la función pivot. Además, pivot_table también tiene un argumento aggfunc que especifica la operación de agregación que se aplicará a los valores. Por defecto, el valor de aggfunc es mean, pero puede especificarse una variedad de operaciones como sum, count, max, min, std, var, y muchas más.
import pandas as pd
datos = {
'Fecha': ['2022-01-01', '2022-01-01', '2022-01-02', '2022-01-02', '2022-01-03', '2022-01-03'],
'Vendedor': ['Juan', 'Pedro', 'Juan', 'Pedro', 'Juan', 'Pedro'],
'Producto': ['A', 'B', 'A', 'B', 'A', 'B'],
'Ventas': [100, 200, 150, 250, 120, 180]
}
df = pd.DataFrame(datos)
1.- Pivot_table simple: si queremos ver las ventas totales por vendedor y por fecha, podemos hacer lo siguiente:
pivot_df = df.pivot_table(index='Fecha', columns='Vendedor', values='Ventas', aggfunc='sum')
pivot_df
| Vendedor | Juan | Pedro |
|---|---|---|
| Fecha | ||
| 2022-01-01 | 100 | 200 |
| 2022-01-02 | 150 | 250 |
| 2022-01-03 | 120 | 180 |
2.- Pivot_table con agregación múltiple: si queremos ver la suma y el promedio de ventas por vendedor y por fecha, podemos hacer lo siguiente:
pivot_df = df.pivot_table(index='Fecha', columns='Vendedor', values='Ventas', aggfunc=['sum', 'mean'])
pivot_df
| sum | mean | |||
|---|---|---|---|---|
| Vendedor | Juan | Pedro | Juan | Pedro |
| Fecha | ||||
| 2022-01-01 | 100 | 200 | 100.0 | 200.0 |
| 2022-01-02 | 150 | 250 | 150.0 | 250.0 |
| 2022-01-03 | 120 | 180 | 120.0 | 180.0 |
3.- Pivot_table con margen: si queremos ver la suma de ventas por vendedor, por fecha y por el total, podemos hacer lo siguiente:
pivot_df = df.pivot_table(index='Fecha', columns='Vendedor', values='Ventas', aggfunc='sum', margins=True)
pivot_df
| Vendedor | Juan | Pedro | All |
|---|---|---|---|
| Fecha | |||
| 2022-01-01 | 100 | 200 | 300 |
| 2022-01-02 | 150 | 250 | 400 |
| 2022-01-03 | 120 | 180 | 300 |
| All | 370 | 630 | 1000 |
Observación: Las principales diferencias entre pivot y pivot_table son:
La función
pivotsolo funciona con DataFrames que tienen una única columna de valores que se pueden utilizar como la columna de valores de salida en el DataFrame resultante, mientras que la funciónpivot_tablepuede trabajar con múltiples columnas de valores y aplicar operaciones de agregación en esas columnas. Por lo tanto, la funciónpivot_tablees más versátil.La función
pivotsolo se puede utilizar para reorganizar un DataFrame, mientras que la funciónpivot_tabletambién puede realizar operaciones de agregación en los valores correspondientes a cada combinación de valores de índice y columnas. Por lo tanto, la funciónpivot_tablees más adecuada para tareas más avanzadas de análisis de datos.La función
pivotes más simple y tiene una sintaxis más concisa, mientras que la funciónpivot_tablees más compleja y tiene una sintaxis más detallada. Por lo tanto, si solo necesita reorganizar los datos y no necesita realizar operaciones de agregación, la funciónpivotpuede ser más fácil de usar.
Formato wide a long¶
El despivotear una tabla corresponde al paso de una tabla desde el formato wide al formato long.
Se reconocen dos situaciones:
- El valor indicado para la columna es único, y sólo se requiere definir correctamente las columnas.
- El valor indicado por la columna no es único, y se requiere una iteración más profunda.
Para despivotear un dataframe en Pandas, utilizaremos el comando melt.
Melt¶
La función melt en Pandas es una herramienta útil para transformar un DataFrame de formato ancho a formato largo. La función toma como entrada un DataFrame con una o más columnas que se identifican como identificadores (o "id_vars" en inglés), y las convierte en una o más columnas de valor (o "value_vars" en inglés).
La sintaxis básica de la función melt es la siguiente:
pd.melt(
df,
id_vars=['Columna1', 'Columna2'],
value_vars=['Columna3', 'Columna4'],
var_name='NuevaColumna1',
value_name='NuevaColumna2'
)
donde:
df: es el DataFrame que se va a fundir.id_vars: son las columnas del DataFrame que se van a conservar como identificadores.value_vars: son las columnas que se van a fundir en una sola columna.var_name: es el nombre de la columna que contendrá los nombres de las columnas fundidas.value_name: es el nombre de la columna que contendrá los valores de las columnas fundidas.
1.- Ejemplo Sencillo - relaciones únicas: separar correctamente la columna "ingreso".
import pandas as pd
datos = {'Nombre': ['Ana', 'Juan', 'Pedro'],
'Edad': [25, 30, 35],
'Ingreso_2019': [2000, 3000, 4000],
'Ingreso_2020': [2200, 3200, 4200]}
df = pd.DataFrame(datos)
df
| Nombre | Edad | Ingreso_2019 | Ingreso_2020 | |
|---|---|---|---|---|
| 0 | Ana | 25 | 2000 | 2200 |
| 1 | Juan | 30 | 3000 | 3200 |
| 2 | Pedro | 35 | 4000 | 4200 |
# aplicar comando melt
df_melt = pd.melt(
df,
id_vars=['Nombre', 'Edad'],
value_vars=['Ingreso_2019', 'Ingreso_2020'],
var_name='Año',
value_name='Ingreso'
)
df_melt
| Nombre | Edad | Año | Ingreso | |
|---|---|---|---|---|
| 0 | Ana | 25 | Ingreso_2019 | 2000 |
| 1 | Juan | 30 | Ingreso_2019 | 3000 |
| 2 | Pedro | 35 | Ingreso_2019 | 4000 |
| 3 | Ana | 25 | Ingreso_2020 | 2200 |
| 4 | Juan | 30 | Ingreso_2020 | 3200 |
| 5 | Pedro | 35 | Ingreso_2020 | 4200 |
2.- Ejemplo Complejo - relaciones no únicas: separar correctamente la columna "ingreso" y "edad".
import pandas as pd
datos = {'id': ['001', '002', '003'],
'Nombre': ['Juan', 'Ana', 'Pedro'],
'Edad_2019': [25, 32, 28],
'Edad_2020': [26, 33, 29],
'Edad_2021': [27, 34, 30],
'Salario_2019': [2500, 3200, 2800],
'Salario_2020': [2700, 3400, 2900],
'Salario_2021': [2900, 3600, 3000]}
df = pd.DataFrame(datos)
df
| id | Nombre | Edad_2019 | Edad_2020 | Edad_2021 | Salario_2019 | Salario_2020 | Salario_2021 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 001 | Juan | 25 | 26 | 27 | 2500 | 2700 | 2900 |
| 1 | 002 | Ana | 32 | 33 | 34 | 3200 | 3400 | 3600 |
| 2 | 003 | Pedro | 28 | 29 | 30 | 2800 | 2900 | 3000 |
# caso 01: edad
cols_1 = ['id', 'Nombre', 'Edad_2019', 'Edad_2020', 'Edad_2021']
df1 = df[cols_1]
df1.columns = ['id', 'Nombre', '2019', '2020', '2021']
df_melt_01 = pd.melt(df1, id_vars=['id', 'Nombre'], var_name='Fecha', value_name='Edad')
# caso 02: salario
cols_2 = ['id', 'Nombre', 'Salario_2019','Salario_2020', 'Salario_2021']
df2 = df[cols_2]
df2.columns = ['id', 'Nombre', '2019', '2020', '2021']
df_melt_02 = pd.melt(df2, id_vars=['id', 'Nombre'], var_name='Fecha', value_name='Salario')
# juntar informacion
df_melt = df_melt_01.merge(df_melt_02,on = ['id','Nombre','Fecha'])
df_melt
| id | Nombre | Fecha | Edad | Salario | |
|---|---|---|---|---|---|
| 0 | 001 | Juan | 2019 | 25 | 2500 |
| 1 | 002 | Ana | 2019 | 32 | 3200 |
| 2 | 003 | Pedro | 2019 | 28 | 2800 |
| 3 | 001 | Juan | 2020 | 26 | 2700 |
| 4 | 002 | Ana | 2020 | 33 | 3400 |
| 5 | 003 | Pedro | 2020 | 29 | 2900 |
| 6 | 001 | Juan | 2021 | 27 | 2900 |
| 7 | 002 | Ana | 2021 | 34 | 3600 |
| 8 | 003 | Pedro | 2021 | 30 | 3000 |