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
.
index
se utiliza para especificar la(s) columna(s) que se utilizarán como el índice en el DataFrame resultantecolumns
se utiliza para especificar la columna que se utilizará como las columnas en el DataFrame resultantevalues
se 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
pivot
solo 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_table
puede trabajar con múltiples columnas de valores y aplicar operaciones de agregación en esas columnas. Por lo tanto, la funciónpivot_table
es más versátil.La función
pivot
solo se puede utilizar para reorganizar un DataFrame, mientras que la funciónpivot_table
tambié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_table
es más adecuada para tareas más avanzadas de análisis de datos.La función
pivot
es más simple y tiene una sintaxis más concisa, mientras que la funciónpivot_table
es 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ónpivot
puede 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 |