Pandas en Python, con ejemplos -Parte III- Pivot_table
El proyecto de este post lo puedes descargar pulsando AQUI.
Sobre la librería de Pandas vamos a hablar de los siguientes temas en las entradas:
- Parte I: Introducción a Pandas.
- Parte II: DataFrame: Lectura y Escritura, Mergeo de DataFrame's y GroupBy.
- Parte III: Operaciones de "Pivot_table" con DataFrame's.
Pivot_table
La funcionlidad "Pivot_table" es muy utilizada y popular en las conocidas "hojas de cálculo" tipo, OpenOffice, LibreOffice, Excel, Lotus, etc. Esta funcionalidad nos permite agrupar, ordenar, calcular datos y manejar datos de una forma muy similar a la que se hace con las hojas de cálculo.
Esta función de pandas admite los siguientes parámetros, que podéis consultar con más detalle pulsando AQUI:
DataFrame.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True)
La principal función del "Pivot_table" son las agrupaciones de datos a las que se les suelen aplicar funciones matemáticas como sumatorios, promedios, etc. Si no indicamos en el parámetro 'aggfunc' que opereción queremos hacer; por defecto, nos calculará la media de todas aquellas columnas que sean de tipo numérico.
Pasemos a ver un primer ejemplo, en el que vamos a utilizar el dataset de MovieLens con 100K votos. Para ello leeremos los datos de los ficheros en los que tenemos la información de los usuarios, las películas y los votos al igual que hicimos en la entrada "DataFrame: Lectura y Escritura, Mergeo de DataFrame's y GroupBy":
import pandas as pd import numpy as np # Load Data userHeader = ['user_id', 'gender', 'age', 'ocupation', 'zip'] users = pd.read_table('dataSet/users.txt', engine='python', sep='::', header=None, names=userHeader) movieHeader = ['movie_id', 'title', 'genders'] movies = pd.read_table('dataSet/movies.txt', engine='python', sep='::', header=None, names=movieHeader) ratingHeader = ['user_id', 'movie_id', 'rating', 'timestamp'] ratings = pd.read_table('dataSet/ratings.txt', engine='python', sep='::', header=None, names=ratingHeader) # Merge data mergeRatings = pd.merge(pd.merge(users, ratings), movies)
ADVERTENCIA!! para la copia o "clone" de DataFrame's:
A continuación comparto un método ('cloneDF(df)') devuelve una copia del DataFrame que se pasa como parámetro:
# Clone DataFrame def cloneDF(df): return pd.DataFrame(df.values.copy(), df.index.copy(), df.columns.copy()).convert_objects(convert_numeric=True)
El primer ejemplo que vamos a ver, va a ser el de poner como índices las columnas de 'movie_id' y 'title'. De esta forma, nos hará una agrupación por título e identificador de la película. Esto lo hacemos de la siguiente manera:
# Simple pivot (Groupby + avg) df_1 = cloneDF(mergeRatings) df_1 = df_1.pivot_table(index=['movie_id', 'title']) print 'Columns(movie_id + title) to Index: \n%s' % df_1[:5]
Como resultado, vamos a obtener los 5 primeros elementos de esta agrupación del DataFrame y al no indicarle el parámetro 'aggfunc' nos calculará la media de todos los valores numéricos:
age ocupation rating .... movie_id title 1 Toy Story (1995) 27.700530 8.067886 4.146846 .... 2 Jumanji (1995) 27.800285 7.680456 3.201141 .... 3 Grumpier Old Men (1995) 29.276151 7.826360 3.016736 .... 4 Waiting to Exhale (1995) 27.788235 6.752941 2.729412 .... 5 Father of the Bride Part II (1995) 27.425676 7.506757 3.006757 ....
Podemos hacer esta misma operación indicandole con el parámetros 'values' sobre que columnas queremos que nos calcule la media; ya que como vemos no tiene mucho sentido que nos calcule la media de la columna "ocupation" que es un identificador de la profesión de cada usuario. Pasamos a indicarle (con "values=[‘rating’, ‘age’]") que solo nos calcule el valor medio de la agrupación de las columnas 'rating' y 'age':
df_2 = cloneDF(mergeRatings) df_2 = df_2.pivot_table(index=['movie_id', 'title'], values=['rating', 'age']) print 'Columns(movie_id + title) to Index and avg by values \n%s' % df_2[:5]
Como resultado tenemos lo siguiente:
Columns(movie_id + title) to Index and avg by values age rating movie_id title 1 Toy Story (1995) 27.700530 4.146846 2 Jumanji (1995) 27.800285 3.201141 3 Grumpier Old Men (1995) 29.276151 3.016736 4 Waiting to Exhale (1995) 27.788235 2.729412 5 Father of the Bride Part II (1995) 27.425676 3.006757
El siguiente paso que vamos a dar, es el de indicarle que operaciones queremos hacer y sobre que columna. En este caso vamos ha "pivotar" sobre el título de la película y su identificador, y vamos a aplicar sobre la columna 'rating' las operaciones de sumatorio, conteo y media. Para hacer estos cálculo haremos uso de la librería 'numpy':
df_3 = cloneDF(mergeRatings) df_3 = df_3.pivot_table(index=['movie_id', 'title'], values=['rating'], aggfunc=[np.sum, np.size, np.mean]) print 'Columns(movie_id + title) to Index and specific functions by values \n%s' % df_3[:5]
Como resultado tenemos lo siguiente:
Columns(movie_id + title) to Index and specific functions by values sum size mean rating rating rating movie_id title 1 Toy Story (1995) 8613 2077 4.146846 2 Jumanji (1995) 2244 701 3.201141 3 Grumpier Old Men (1995) 1442 478 3.016736 4 Waiting to Exhale (1995) 464 170 2.729412 5 Father of the Bride Part II (1995) 890 296 3.006757
Como último ejemplo vamos a seguir agrupando por título e identificador de película y aplicaremos sobre la columna 'rating' la función que nos calcule la media de sus valores pasándole el parámetro 'aggfunc', pero en este caso vamos a indicarle con el parámetro 'columns' que nos muestre en columnas separadas todos los valores distintos que tiene en este caso la columna 'gender' (columns=[‘gender’]) y además con el parámetro 'margins=True' le indicaremos que añada una nueva columna con los cálculos de todos lo valores. En resumen, tendremos como resultado una agrupación por película e identificador en el que veremos el votos medio que realizan los hombres y las mujeres por separado y (con el parámetro 'margins=True') el voto de la película. Esto lo hacemos de la siguiente manera:
df_4 = cloneDF(mergeRatings) df_4 = df_4.pivot_table(index=['movie_id', 'title'], values=['rating'], columns=['gender'], aggfunc=[np.mean], fill_value=-1, margins=True) print 'Columns(movie_id + title) to Index and avg rating applied by gender \n%s' % df_4[:5]
Como resultado tenemos lo siguiente:
Columns(movie_id + title) to Index and avg rating applied by gender mean rating gender F M All movie_id title 1 Toy Story (1995) 4.187817 4.130552 4.146846 2 Jumanji (1995) 3.278409 3.175238 3.201141 3 Grumpier Old Men (1995) 3.073529 2.994152 3.016736 4 Waiting to Exhale (1995) 2.976471 2.482353 2.729412 5 Father of the Bride Part II (1995) 3.212963 2.888298 3.006757
Podemos observar como de diferentes votan los hombres y las mujeres; por ejemplo, la película "Waiting to Exhale" parece que les gusta algo más a los hombres que a las mujeres ya que les separa casi 0.5 puntos de media.
CONCLUSIONES:
La librería de Pandas es una librería destinada al análisis de datos muy utilizada por los 'data scientists' y como se ha podido obversar en este tutorial, hemos podido analizar datos relacionados con los votos emitidos por personas sobre películas y gracias a las operaciones de "Pivot_table" hemos sacado algunos datos que pueden ser relevantes. Dado que es un tutorial de introducción se han visto pocas cosas operaciones con "Pivot_table", pero si que se han visto las necesarias como para empezar a trabajar con esta funcionalidad y una vez que se tenga soltura, seguro que podréis hacer un análisis de datos muy exhaustivo y preciso ya que es una librería que utilizan hoy en dia los data scientists profesionales.