El cálculo de estadísticas no nos permite contar la historia completa de los datos con los que trabajamos.
¿Por qué visualizar?
La visualización de datos es más que la representación gráfica de información. Es una forma de comunicación visual orientada a generar conocimiento acerca de los datos.
Las herramientas de visualización ayudan a poner en evidencia información relevante sobre un dataset, facilitando la detección de tendencias, patrones, valores atípicos y correlaciones entre variables.
Visualización de datos en Python
MATPLOTLIB. Es una extensa biblioteca de funciones para generar figuras 2D y 3D adecuadas para su publicación. Destaca su módulo pyplot.
Visualización de datos en Python
SEABORN. Es una librería de gráficos de alto nivel construida sobre matplotlib, que simplifica la creación de diversas visualizaciones de uso común.
Visualización de datos en Python
PLOTNINE. Es una implementación de Grammar of Graphics (libro escrito por Leland Wilkinson en 1999) en Python, basada en ggplot2 de R. La gramática de los gráficos de Wilkinson provee un sistema para combinar elementos gráficos que den como resultado figuras para mostrar datos de manera visualmente significativa.
Clasificación según Claus Wilke
Claus Wilke propone una clasificación de las herramientas de visualización según el objetivo que se persigue. Por ejemplo:
Gráficos para visualizar distribuciones
Gráficos para visualizar cantidades y proporciones
Gráficos para visualizar relaciones entre dos variables cuantitativas
Gráficos para datos geoespaciales
Visualizar distribuciones
Alternativas para visualizar una única distribución:
Visualizar distribuciones
Alternativas para visualizar varias distribuciones al mismo tiempo:
Visualizar proporciones
Relaciones entre variables cuantitativas
Relaciones entre variables cuantitativas
Visualizar datos geoespaciales
GRÁFICOS PARA VISUALIZAR DISTRIBUCIONES (vars. cuantitativas)
GRÁFICOS PARA VISUALIZAR DISTRIBUCIONES
Recuperemos el dataset data_ejercicio.csv con el que trabajamos en la Unidad anterior.
Supongamos, en primer lugar, que deseamos construir un gráfico para visualizar la distribución de las observaciones de la variable edad_anios.
¿De qué hablamos cuando hablamos de DISTRIBUCIÓN?
Cuando hablamos de la distribución de las observaciones de una variable, nos referimos a cómo están “organizados” o “repartidos” los valores de esa variable, es decir, cuántas veces aparece cada valor o cada rango de valores.
GRÁFICO DE BASTONES
Cuando el número de observaciones es grande pero hay pocos valores diferentes, como ocurre generalmente cuando la variable es discreta, el gráfico o diagrama de bastones es la representación gráfica adecuada en este caso.
En el eje de abscisas se representan los valores observados de la variable y en el de ordenadas, las correspondientes frecuencias (absolutas o relativas). Luego, para cada valor observado se levanta un segmento o bastón de altura igual a su frecuencia.
GRÁFICO DE BASTONES
Es decir que este tipo de representación toma como punto de partida la tabla de frecuencias correspondiente para las observaciones de la variable, que constituye una forma de resumir la distribución de dichos valores en el dataset.
Acá, las primeras filas de dicha tabla de frecuencias:
Podemos construir un gráfico de este tipo para la variable edad utilizando la función countplot() de la librería seaborn, seteando el parámetro width en un valor pequeño de manera que lo que se muestren sean bastones y no barras.
La variable que se muestra en el eje y puede modificarse a través del parámetro stat, pudiendo ser: count (default), percent o proportion.
⚠️IMPORTANTE: en este caso, es fundamental agregar la especificación correspondiente en el parámetro order, ya que de lo contrario obtenemos un gráfico que omite, en la escala del eje x, la edad de 16 años. Esto vuelve la escala incorrecta.
El problema es que, como no hay personas de 16 años en los datos, la frecuencia para esa edad es cero. Si no se indica manualmente el orden, Seaborn no deja un espacio vacío en el gráfico para representar ese valor ausente. Esto puede inducir a error al interpretar la distribución.
HISTOGRAMA DE FRECUENCIAS
Un gráfico muy utilizado para representar datos de una variable continua (especialmente cuando el número de observaciones es grande) es el histograma de frecuencias.
En el eje de las abscisas se representan intervalos en que se agrupan los valores de la variable (recordar clases pasadas) y en el eje de las ordenadas, la frecuencia absoluta o relativa. Luego, sobre cada uno de los subintervalos se grafica un rectángulo cuya área representa la frecuencia (absoluta o relativa) del mismo.
HISTOGRAMA DE FRECUENCIAS
Podemos construir este tipo de visualización utilizando la función histplot() de la librería seaborn. Veamos cómo luce el histograma de las observaciones de calorias_quemadas:
sns.histplot(x ='calorias_quemadas', data = df);
HISTOGRAMA DE FRECUENCIAS
Por default, el número de subintervalos en los que se segmenta la variable (bins) es calculado por la función de seaborn utilizando algún método predefinido que toma en cuenta la cantidad de observaciones que se quieren representar.
¿Qué efecto produce la modificación del número de bins sobre el gráfico resultante?
HISTOGRAMA DE FRECUENCIAS
HISTOGRAMA DE FRECUENCIAS
Otro ejemplo con las edades de los pasajeros del Titanic:
HISTOGRAMA DE FRECUENCIAS
El parámetro bins de sns.histplot() puede estar dado por:
el nombre de algún método o regla de referencia: por ejemplo, bins = 'sqrt', para que utilice el criterio de la raíz cuadrada de n para el número de bins.
el número de bins: por ejemplo, bins = 10.
una lista con los breaks que definen los subintervalos: por ejemplo, bins = [0, 5, 10, 15, 20].
Otros parámetros que puede ser útil setear son binwidth y binrange.
HISTOGRAMA DE FRECUENCIAS
Para ver otro tipo de distribución, representemos gráficamente la distribución de las observaciones de la variable peso_kg:
sns.histplot(x ='peso_kg', data = df);
HISTOGRAMA DE FRECUENCIAS
🤔 ¿Qué forma tiene la distribución de los pesos de las personas del dataset?
“EMPROLIJAR EL GRÁFICO”
Siempre que presentemos un gráfico, es importante que los ejes estén correctamente etiquetados:
sns.histplot(x ='peso_kg', data = df)plt.xlabel('Peso (kg)', fontweight ='bold')plt.ylabel('N° de personas', fontweight ='bold');
“EMPROLIJAR EL GRÁFICO”
Podemos modificar la escala del eje x utilizando xticks y definiendo la secuencia con la ayuda de np.arange():
import numpy as npsns.histplot(x ='peso_kg', data = df)plt.xticks(np.arange(30, 81, 5));
GRÁFICO DE DENSIDAD
Un gráfico de densidad intenta visualizar la distribución de probabilidad subyacente de los datos mediante el dibujo de una curva continua apropiada, la cual debe ser estimada a partir de los datos.
El método de estimación más comúnmente utilizado se conoce como estimación de densidad por kernel.
ESTIMACIÓN DE DENSIDAD POR KERNEL
En la estimación de densidad por kernel, dibujamos una curva continua llamada kernel con un ancho pequeño (controlado por un parámetro llamado ancho de banda) en la ubicación de cada punto de datos, y luego sumamos todas estas curvas para obtener la estimación final de densidad.
El kernel más utilizado es un kernel gaussiano, pero hay muchas otras opciones.
GRÁFICO DE DENSIDAD
Para hacer un gráfico de densidad a partir de las observaciones de la variable calorias_quemadas podemos utilizar la función kdeplot() de seaborn:
sns.kdeplot(x ='calorias_quemadas', fill =True, data = df);
GRÁFICO DE DENSIDAD
La apariencia visual exacta de un gráfico de densidad dependerá tanto de la elección del ancho de banda como del tipo de kernel. La primera característica puede modificarse dentro del parámetro bw_method de sns.kdeplot(), el cual puede ser:
el nombre de un método utilizado para estimar el bandwidth según ciertos criterios: por ejemplo, bw_method = 'scott' (default).
un valor de ancho de banda específico: por ejemplo: bw_method = 0.5.
¿Qué efecto produce la modificación del ancho de banda (bandwidth) sobre el gráfico resultante?
GRÁFICO DE DENSIDAD
GRÁFICO DE DENSIDAD
La trampa de los gráficos de densidad.
😱 Las estimaciones de densidad por kernel tienen una trampa de la que debemos ser conscientes: tienden a producir la apariencia de que hay datos donde no existen, en particular en las colas.
🤓 Para evitar que el gráfico se extienda hacia valores que resultan inconsistentes para el tipo de variable con el que trabajamos (por ejemplo, valores negativos de calorías quemadas), podemos setear el parámetro clip de manera de “cortar” el gráfico de densidad en puntos específicos del eje.
GRÁFICO DE DENSIDAD
Sobre la escala del eje “Densidad”.
Como estimaciones de las distribuciones de probabilidad de variables continuas, las curvas de densidad suelen escalarse de manera que el área bajo la curva sea igual a uno. Esta convención puede hacer que la escala del eje y sea confusa, ya que depende de las unidades del eje x.
HISTOGRAMA + GRÁFICO DE DENSIDAD
Seteando el parámetro kde = True de sns.histplot() podemos superponer la curva de densidad por Kernel al histograma:
sns.histplot(x ='peso_kg', kde =True, data = df);
GRÁFICOS PARA COMPARAR DISTRIBUCIONES (vars. cuantitativas)
GRÁFICOS DE DENSIDAD MÚLTIPLES
Si quisiéramos visualizar la distribución de calorias_quemadas ya no en forma general sino segmentada según actividad podemos setear los siguientes parámetros dentro de sns.kdeplot():
hue = 'actividad', para representar con un color distinto la distribución de la variable para cada actividad física (trotar/caminar/correr).
multiple = 'layer', para superponer las distintas curvas.
GRÁFICOS DE DENSIDAD MÚLTIPLES
sns.kdeplot(x ='calorias_quemadas', hue ='actividad', multiple ='layer', fill =True, data = df);
GRÁFICOS DE DENSIDAD MÚLTIPLES
Superponer el gráfico de densidad “general”, ayuda a visualizar qué proporción representa, sobre el total, cada una de las actividades:
sns.kdeplot(x ='calorias_quemadas', hue ='actividad', multiple ='layer', fill =True, data = df)sns.kdeplot(x ='calorias_quemadas', fill =True, data = df);
GRÁFICOS DE DENSIDAD MÚLTIPLES
Porcentaje que representa cada actividad sobre el total:
Luego lo incluimos como parte del parámetro order:
sns.boxplot(x ='calorias_quemadas', y ='actividad', hue ='actividad', order = orden_segun_mediana, data = df);
🤓 ¡Manos a la obra!
En visualizaciones con boxplots múltiples, es común superponer también la media aritmética de cada grupo para complementar la información que aporta la mediana.
📌 Sobre el boxplot múltiple de calorías quemadas según el tipo de actividad física, agregar al gráfico la media de cada grupo, representándola con un punto negro relleno.
STRIP PLOTS o JITTER PLOTS
Los jitter plots son gráficos en los que se representan directamente todos los datos individuales en la forma de puntos.
Cuando hay muchos datos, para no graficar demasiados puntos uno encima del otro, los mismos se dispersan un poco añadiendo algo de ruido aleatorio en la dimensión en la que se plotean (técnica llamada “jittering”).
Constituyen una buena herramienta para visualizar múltiples distribuciones.
STRIP PLOTS o JITTER PLOTS
Podemos construir uno con los datos de calorias_quemadas según actividad utilizando la función stripplot() de seaborn. El grado de “jittering” se setea a través del parámetro jitter.
sns.stripplot(x ='calorias_quemadas', y ='actividad', hue ='actividad', order = orden_segun_mediana, jitter =0.25, data = df);
VIOLIN PLOT
Los gráficos de violín (violin plots) son gráficos de densidad por Kernel espejados.
Se pueden usar en los mismos casos en los que podríamos optar por un boxplot, y a diferencia de este tipo de gráfico ofrecen una representación mucho más matizada de los datos que posibilita la detección de distribuciones bi/multimodales.
VIOLIN PLOT
Podemos construir uno con los datos de calorias_quemadas según actividad utilizando la función violinplot() de seaborn.
sns.violinplot(x ='calorias_quemadas', y ='actividad', hue ='actividad', order = orden_segun_mediana, gap =1.7, data = df);
VIOLIN PLOT
Por default, la visualización incorpora un boxplot interno que puede ocultarse seteando el parámetro inner = None o “tunearse” introduciendo modificaciones en la forma de un diccionario dentro de inner_kws.
Por otra parte, otro parámetro que permite modificar la apariencia de la visualización es gap, para introducir cambios en el grosor del gráfico de violín.
STRIP PLOT + VIOLIN PLOT
Los dos últimos gráficos pueden combinarse para crear una visualización muy interesante:
sns.violinplot(x ='calorias_quemadas', y ='actividad', hue ='actividad', data = df, order = orden_segun_mediana, inner =None)sns.stripplot(x ='calorias_quemadas', y ='actividad', data = df, color ='black', size =3, dodge =True, linewidth =1, edgecolor ='gray', jitter =True, alpha =0.7);
GRÁFICOS PARA VISUALIZAR PROPORCIONES (vars. cualitativas)
REPRESENTAR VARIABLES CUALITATIVAS
Uno de los gráficos más utilizados para representar datos de variables cualitativas son los gráficos de barras.
En este tipo de gráficos, se representa una barra (por lo general, horizontal) para cada categoría. La longitud de cada una de ellas es proporcional al porcentaje de unidades que pertenecen a la categoría y el ancho es el mismo para todas.
DATASET TITANIC
Para ver algunos ejemplos de gráficos de barras, vamos a trabajar con el dataset titanic. El mismo viene incorporado en seaborn y contiene información relacionada con los pasajeros del barco.
Podemos cargar el dataset en el entorno de trabajo utilizando el siguiente comando:
titanic = sns.load_dataset('titanic')
🤓 ¡Manos a la obra!
1. Importar el dataset al entorno de trabajo utilizando la función load_dataset() de Seaborn.
2. Generar una tabla de frecuencias con la distribución de pasajeros según la clase. La misma debe contener tanto las frecuencias absolutas de las diferentes categorías como los porcentajes correspondientes.
3. Generar una tabla con la distribución conjunta de pasajeros según clase y supervivencia. La tabla debe contener sólo los porcentajes correspondientes.
PASAJEROS DE CADA CLASE
Podemos representar la distribución de pasajeros que viajaron en cada clase (class) utilizando un gráfico de barras:
sns.countplot(y ='class', stat ='percent', order = ['First', 'Second', 'Third'], data = titanic);
BARRAS AGRUPADAS o PARALELAS
A menudo estamos interesados en visualizar dos variables categóricas al mismo tiempo. Esto puede hacerse a través de un gráfico de barras paralelas o agrupadas.
En este tipo de gráficos, representamos un grupo de barras en cada posición a lo largo del eje y, de acuerdo a los distintos niveles de una primera variable categórica, y luego relacionamos cada una de las barras del grupo a un nivel diferente de una segunda variable categórica.
BARRAS AGRUPADAS o PARALELAS
Para construir un gráfico de barras paralelas que muestre los porcentajes de pasajeros según la clase en la que viajaron y si sobrevivieron o no (alive), podemos setear, en el gráfico anterior, el parámetro hue = 'alive'.
sns.countplot(y ='class', hue ='alive', stat ='percent', order = ['First', 'Second', 'Third'], data = titanic);
BARRAS AGRUPADAS o PARALELAS
🤔 ¿Qué tipo de información nos brinda este gráfico?
BARRAS AGRUPADAS o PARALELAS
Los porcentajes de cada combinación de categorías están calculados sobre el total. Podríamos acceder a esa información realizando una operación previa de groupby() por las columnas class y alive, y luego calcular los porcentajes correspondientes:
class alive
First no 8.98
yes 15.26
Second no 10.89
yes 9.76
Third no 41.75
yes 13.36
dtype: float64
GRÁFICO DE BARRAS APILADAS
Otra forma de mostrar la información anterior podría ser a través de un gráfico de barras apiladas o stackeadas.
Para construir este tipo de visualización, necesitamos generar previamente de una tabla de doble entrada, lo que podemos hacer con la combinación de los métodos size() y unstack() de la librería Pandas, previo agrupamiento las columnas class y alive:
alive no yes
class
First 80 136
Second 97 87
Third 372 119
GRÁFICO DE BARRAS APILADAS
Luego podemos usar el método plot.barh() de Pandas para construir el gráfico deseado, con el argumento stacked = True para mostrar barras apiladas:
tabla_freq.plot.barh(stacked =True)
GRÁFICO DE BARRAS APILADAS
Si quisiéramos ahora que los porcentajes estén calculados sobre el total de personas que viajaron en cada clase (y no sobre el total general de pasajeros), tendríamos que generar una tabla de doble entrada con dichos porcentajes.
Esto lo podemos hacer sobre la tabla de doble entrada generada anteriormente utilizando el método div() de Pandas:
alive no yes
class
First 37.04 62.96
Second 52.72 47.28
Third 75.76 24.24
GRÁFICO DE BARRAS APILADAS
En el código anterior, tabla_freq.sum(axis = 1) calcula la suma total de personas para cada clase.
tabla_freq.sum(axis =1)
class
First 216
Second 184
Third 491
dtype: int64
tabla_freq.div(tabla_freq.sum(axis = 1), axis = 0) divide cada valor de la tabla tabla_freq entre el total de personas por clase. El argumento axis = 0 indica que la división se realiza por filas.
GRÁFICO DE BARRAS APILADAS
Finalmente, nos queda graficar la info contenida en la tabla de porcentajes que generamos:
Más allá de colores y anchos de barras, ¿cuál es la principal diferencia entre estos dos gráficos que construimos?
PARA CERRAR LA SECCIÓN
El primer gráfico muestra la distribución conjunta de las variables class y alive en el total de los datos, es decir, en el total de pasajeros que viajaban en el Titanic. Para llegar al 100%, hay que sumar los porcentajes de todas las barras.
El título podría ser: “Distribución de pasajeros del Titanic según clase y supervivencia al naufragio”.
PARA CERRAR LA SECCIÓN
El segundo gráfico muestra la distribución condicional de la supervivencia al naufragio dada la clase en la que viajaba el pasajero. Los porcentajes suman 100% dentro de cada una de las clases.
El título podría ser: “Supervivencia al naufragio de los pasajeros según la clase en la que viajaban”.
GRÁFICO DE SECTORES
La construcción del gráfico de sectores consiste en diagramar un círculo que representa al 100% de las unidades. El mismo se divide en tantos sectores como categorías existan y el área de cada uno de los sectores es proporcional al porcentaje de unidades que pertenecen a la categoría que representa.
GRÁFICO DE SECTORES
Podemos construir un gráfico de sectores para las observaciones de class generando previamente una tabla que contenga los porcentajes correspondientes a cada una de las tres categorías: