Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Clase 4: Librería Seaborn-Conceptos intermedios
Fecha: 10 de diciembre del 2022
En clases anteriores indagamos en los conceptos más básicos sobre seaborn, asimismo, logramos escalar a temas un poco más complejos. Ahora, con esta clase indagaremos en temas más avanzados sobre la librería Seaborn.
Un histograma es una representación gráfica de una variable en forma de barras y nos sirve para ver la distribución de dicha variable. De tal manera, los histogramas nos permiten dar un vistazo al comportamiento, variabilidad o dispersión de una variable cuantitativa.
Por ejemplo, graficaremos el histograma de la variable sepal_length
del conjunto de datos iris
# Importaciones necesarias
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# Cargamos el conjunto de datos
df = sns.load_dataset('iris')
df
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica |
150 rows × 5 columns
# Graficamos el histograma
g = sns.displot(data=df, x='sepal_length', kde=True)
donde kde hace alusión a la curva de estimación de densidad del kernel$\ ^{(1)}$, el cual sirve para visualizar la distribución de observaciones en un conjunto de datos, y tiene un uso similar a un histograma, por lo cual en ocasiones es conveniente visualizarlos simultáneamente. Si no queremos ver dicha curva configuramos kde=False
, o simplemente no colocamos dicho parámetro dentro de la función displot()
.
$(1)$ KDE representa los datos utilizando una curva de densidad de probabilidad continua.
Por otro lado, podemos realizar el gráfico de la curva kde de manera individual
g = sns.kdeplot(data=df, x="sepal_length")
O de manera alternativa:
g = sns.displot(data=df, x='sepal_length',
kind='kde')
# Podemos rellenar el area debajo de la curva kde
g = sns.displot(data=df, x='sepal_length',
# rellenamos el area debajo de
# la curva
fill=True,
kind='kde')
Gracias a lo anterior nos podemos dar cuenta que la función displot()
es muy similar a las funciones relplot(), catplot()
, de donde displot()
se utiliza para gráficos de distribución y este tipo de función son consideradas de alto nivel (más versátiles) a diferencia de la función kdeplot()
la cual es considerada de bajo nivel.
De tal manera, otro camino para crear un histograma es:
g = sns.displot(data=df, x='sepal_length',
kind='hist')
# Ahora el histograma con la curva kde
g = sns.displot(data=df, x='sepal_length',
kde=True,
kind='hist')
La curva ECDF (Empirical cumulative Distribution Function), o también denominada curva de la función de distribución acumulada, representa la proporción o el recuento de observaciones que caen por debajo de cada valor único en un conjunto de datos. En comparación con un histograma o un gráfico de densidad, tiene la ventaja de que cada observación se visualiza directamente.
Para crear una curva ECDF escribimos
# graficamos la curva ecdf
sns.displot(data=df, x='sepal_length',
kind='ecdf')
# lineas auxiliares
plt.plot([6,6], [0, 0.549], color='orange')
plt.plot([6,0], [0.549, 0.549], color='orange')
plt.show()
donde, por ejemplo, para el valor 6.0 del eje x
podemos decir que alrededor del 55% de los valores almecenado en la columna sepal_length
son menores a 6.0. De tal modo, para el último valor del eje x
podemos decir que el 100% de los valores en la misma columna son menores a dicho valor, esto es, todos los valores de la columna sepal_length
son menores a 8. En efecto, notemos que el valor mayor en esa columna es:
df['sepal_length'].max()
7.9
Básicamente en un análisis de regresión buscamos hallar y describir relaciones, lineales, entre dos variables cuantitativas. Por ejemplo, un primer paso para detectar posibles relaciones lineales entre dos variables es realizando un diagrama de dispersión, por ejemplo
g = sns.relplot(data=df, x='petal_width',
y='petal_length',
kind='scatter')
podemos notar que dichas variables parecen estar relacionadas de manera lineal, donde al aumentar el valor de petal_width
el valor de petal_length
también aumenta. Una vez que el diagrama de dispersión nos ayuda a identificar la posible relación entre dos variables, podemos utilizar el coeficiente de correlación de pearson para comprobar si la relación es lineal o no. Dicho coeficiente va del -1 al 1, donde valores cercanos al 1 nos indica que la relación es lineal, valores cercanos a -1 nos indican que la relación es lineal inversa, es decir que si una variable aumenta la otra disminuye y viceversa. Si el coeficiente está cercano a 0 nos indicará que no hay indicios de relación lineal entre las variables.
Podemos obtener , como vimos en clases anteriores, el coeficiente de correlación de pearson para todas las variables de un dataframe:
df.corr(method='pearson')
sepal_length | sepal_width | petal_length | petal_width | |
---|---|---|---|---|
sepal_length | 1.000000 | -0.117570 | 0.871754 | 0.817941 |
sepal_width | -0.117570 | 1.000000 | -0.428440 | -0.366126 |
petal_length | 0.871754 | -0.428440 | 1.000000 | 0.962865 |
petal_width | 0.817941 | -0.366126 | 0.962865 | 1.000000 |
de donde petal_length
y petal_width
están relacionadas de manera lineal, y así podríamos implementar un análisis de regresión para dichas variables. No indagaremos de manera profunda en el tema de regresión lineal, el cual es muy rico y muy utilizado en la estadística y el aprendizaje automático.
Continuando, podemos realizar un gráfico de regresión para las variables anteriores, para ello utilizamos la función regplot()
como sigue
g = sns.regplot(data=df, x='petal_width',
y='petal_length')
donde vemos el diagrama de dispersión de las variables y además vemos una líneas recta. Dicha línea describe la relación lineal entre las variables. Además podemos ver un intervalo de confianza (el área sombreada alrededor de la recta de regresión) correspondiente a la recta de regresión.
Tenemos que la función regplot()
es de bajo nivel. Para realizar gráficos de regresión de una manera de alto nivel utilizaremos la función lmplot()
:
# Obtenemos el mismo grafico que el anterior
g = sns.lmplot(data=df, x='petal_width',
y='petal_length')
Así, podemos implementar más cosas a la función lmplot()
, como por ejemplo
g = sns.lmplot(data=df, x='petal_width',
y='petal_length',
hue='species')
Lo cual nos da una recta de regresión por especie. O también podemos obtener tres gráficos, uno por especie, con su respectiva recta de regresión.
g = sns.lmplot(data=df, x='petal_width',
y='petal_length',
col='species')
Para finalizar esta parte, realicemos el gráfico de regresión colocando mayor información con etiquetas y títulos, así como personalizando el gráfico:
# creamos una paleta de colores con 3 colores
paleta_custom = ['red', 'green', 'blue']
# especificamos dicha paleta en la funcion set_palette()
sns.set_palette(paleta_custom)
# colocamos un estilo de graficion
sns.set_style('whitegrid')
# grafico de regresion
g = sns.lmplot(data=df, x='petal_width',
y='petal_length',
hue='species')
# Titulo a una altura un poco mayor de la predeterminada
# y aumentamos el tamanio
g.fig.suptitle('Gráfico de regresión', y=1.05, size=16)
# titulos para las etiquetas de los ejes
g.set(xlabel='Ancho del pétalo',
ylabel='Largo del pétalo')
plt.show()
Podemos visualizar la paleta de color que definimos antes:
# a la funcion palplot() le pasamos la pelata de color
sns.palplot(sns.color_palette())
Hay algunas paletas de colores predeterminadas
# algunas paletas predeterminadas
paletas = ['deep', 'muted', 'pastel', 'bright', 'dark', 'colorblind']
# visualizamos las paletas en consola
for _ in paletas:
# elegimos una paleta de la lista anterior
sns.set_palette(_)
# mostramos dicha paleta
sns.palplot(sns.color_palette())
plt.show()
Además, tendremos tres tipos básicos de paletas de colores:
# Por ejemplo
# configuramos que queremos 12 colores
sns.palplot(sns.color_palette('Paired', 12))
# Por ejemplo
sns.palplot(sns.color_palette('Reds', 12))
# Por ejemplo
sns.palplot(sns.color_palette('Blues', 12))
# Por ejemplo
sns.palplot(sns.color_palette('BrBG', 12))
Dado que seaborn está basado en matplotlib, podemos modificar gráficos hechos con seaborn utilizando elementos de matplotlib.
Si pasamos en las funciones de graficación de seaborn un objeto del tipo Axes
de matplotlib, podremos implementar modificaciones a dichos gráficos de seaborn utilizando directamente matplotlib. Para ello deberemos de colorar al inicio dle gráfico el código
fig, ax = plt.subplots()
print(type(ax))
print(type(fig))
<class 'matplotlib.axes._subplots.AxesSubplot'> <class 'matplotlib.figure.Figure'>
fig, ax = plt.subplots()
# Creamos un histograma
sns.histplot(data=df, x='sepal_length',
# al parametro ax pasamos el
# objeto ax
ax=ax)
# podemos colocar una etiqueta al grafico utilizando
# directamente el objeto ax
ax.set(xlabel='Largo del sépalo')
plt.show()
Más aún, podemos colocar las etiquetas de los ejes y un título
fig, ax = plt.subplots()
# Creamos un histograma
sns.histplot(data=df, x='sepal_length',
# al parametro ax pasamos el
# objeto ax
ax=ax)
# podemos colocar una etiqueta al grafico utilizando
# directamente el objeto ax
ax.set(xlabel='Largo del sépalo', ylabel='Distribución',
# agregamos un titulo
title='Histograma',
# podemos personalizar el limite de graficacion
xlim=(3,8.5))
plt.show()
Podemos configurar y combinar múltiples gráficos, para lo cual necesitaremos dos objetos del tipo Axes
, uno por cada gráfico. Y podremos agregar configuraciones nuevas como veremos en la siguiente celda de código
# configuramos el numero filas para
# el grafica y el numero de columnas
fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2,
# tamanio del grafico principal,
# 7 de largo y 4 de ancho
figsize=(7,4))
# Creamos un primer histograma
sns.histplot(data=df, x='sepal_length',
# al parametro ax pasamos el
# objeto ax0
ax=ax0)
# Creamos un segundo histograma, donde dicho histograma
# tendra visible la curva de la densidad
sns.histplot(data=df, x='sepal_length',
stat='density',
# al parametro ax pasamos el
# objeto ax1
ax=ax1)
# Etiquetas para el primer grafico
ax0.set(xlabel='Largo del sépalo', ylabel='Distribución',
# agregamos un titulo
title='Histograma')
# Etiquetas para el segundo grafico
ax1.set(xlabel='Largo del sépalo', ylabel='Distribución',
# agregamos un titulo
title='Histograma con la curva de densidad')
# Podemos agregar una recta vertical para el segundo grafico
ax1.axvline(x=6, linestyle='--', color='blue', label='Línea vertical')
# o una linea horizontal al primer grafico
ax0.axhline(y=15, alpha=0.2, color='blue', label='Línea horizontal')
# mostraremos las legendas
ax0.legend()
ax1.legend()
plt.show()
Una figura (Fig) es una ventana (en el GUI) en la cual se muestran los gráficos. Por ello en la celda de código donde solo colocamos fig, ax = plt.subplots()
se mostró un cuadrículado de gráfico vacío.
Así, por ejemplo, podemos colocar facecolor=
dentro de la función plt.subplots()
para cambiar el color de fondo del dibujo:
fig, ax = plt.subplots(facecolor='black')
Cabe mencionar que la función plt.subplots()
nos permite organizar gráficos en una cuadrícula.
Por otro lado, los ejes (Axes) son muy similares a los subplots, permiten colocar gráficos en cualquier ubicación en la figura, y además nos permite modificar, personalizar y configurar nuestros gráficos, así como vimos en la sección anterior.
Finalmente, una curiosidad que podemos hacer con numpy y matplotlib:
import numpy as np
eqs = []
eqs.append((r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = U^{3\beta}_{\delta_1 \rho_1}" +
r" + \frac{1}{8 \pi 2} \int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 " +
r"\left[\frac{ U^{2\beta}_{\delta_1 \rho_1} " +
r"- \alpha^\prime_2U^{1\beta}_{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$"))
eqs.append((r"$\frac{d\rho}{d t} + \rho \vec{v}\cdot\nabla\vec{v} = " +
r"-\nabla p + \mu\nabla^2 \vec{v} + \rho \vec{g}$"))
eqs.append((r"$\int_{-\infty}^\infty e^{-x^2}dx=\sqrt{\pi}$"))
eqs.append((r"$E = mc^2 = \sqrt{{m_0}^2c^4 + p^2c^2}$"))
eqs.append((r"$F_G = G\frac{m_1m_2}{r^2}$"))
plt.axes([0.025, 0.025, 0.95, 0.95])
for i in range(24):
index = np.random.randint(0, len(eqs))
eq = eqs[index]
size = np.random.uniform(12, 32)
x,y = np.random.uniform(0, 1, 2)
alpha = np.random.uniform(0.25, .75)
plt.text(x, y, eq, ha='center', va='center', color="#11557c", alpha=alpha,
transform=plt.gca().transAxes, fontsize=size, clip_on=True)
plt.xticks(())
plt.yticks(())
plt.show()