Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Clase 1: Librería Seaborn
Fecha: 08 de diciembre del 2022
La librería seaborn es utilizada para las visualizaciones en python, es muy similar a la librería matplotlib, de hecho seaborn está construido a partir de dicha librería. Las visualizaciones dentro del análisis de datos nos sirven para explorar los datos y para, en la etapa final, comunicar los resultados.
Como hemos visto en alguna clase anterior, podemos cargar conjuntos de datos a partir de la librería seaborn:
import seaborn as sns
import matplotlib.pyplot as plt
# cargamos el conjunto de datos iris
df_iris = sns.load_dataset('iris')
df_iris.head()
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 |
Procedemos a realizar un gráfico de dispersión escribiendo:
# primero especificamos el conjunto de datos (data=)
# y despues definimos las variables del eje x y el eje y
sns.scatterplot(data=df_iris, x='petal_width', y='petal_length')
plt.show()
Este tipo de gráficos toman valores categóricos y devuelven barras que representan el número de entradas de cada categoría. Podemos crear un gráfico de conteo para ver cuántos elementos tenemos en nuestro conjunto de datos por especie
# conjunto de datos: data=
# variable categorica: x=
sns.countplot(data=df_iris, x='species')
plt.show()
Luego, retomando el diagrama de dispersión que hicimos antes, podemos agregar colores a los puntos de dicho diagrama, donde la manera de colorear dependera de la especie de la que se trate. Lo anterior lo conseguiremos agregando el parámetro hue=
a la función scatterplot()
, donde configuraremos hue='species'
para hacer que el coloreado se haga con base en la columna species
:
sns.scatterplot(data=df_iris, x='petal_width', y='petal_length', hue='species')
plt.show()
Notamos que en la parte donde se muestran las etiquetas, se muestra primero la especie setosa. Podemos cambiar ese orden:
sns.scatterplot(data=df_iris, x='petal_width', y='petal_length',
hue='species',
# cambiaremos el orden en el que se muestran
# las etiquetas
hue_order=['virginica', 'setosa', 'versicolor'])
plt.show()
Asimismo, vemos que los colores se han asignado de manera automática. Para cambiar los colores necesitaremos definir un diccionario donde las llaves son los nombres de la categoría y los valores son los colores que queremos asignarles. Luego, dicho diccionario será pasado a un nuevo parámetro denominada palette
:
# diccionario
dict_color = {'setosa': 'blue',
'versicolor': 'red',
'virginica': 'green'}
sns.scatterplot(data=df_iris, x='petal_width', y='petal_length',
hue='species',
# cambiaremos el orden en el que se muestran
# las etiquetas
hue_order=['virginica', 'setosa', 'versicolor'],
# cambiamos los colores
palette=dict_color)
plt.show()
Del gráfico anterior vemos que en un mismo diagrama de dispersión hemos colocado la información de las tres categorías en cuestión. En realidad podemos obtener un gráfico por cada categoría, lo cual conseguiremos con la función relplot()
. La gran ventaja de dicha función es crear subgráficos en una misma figura.
Comenzaremos con realizar un diagrama de dispersión como el anterior, pero utilizando ahora la función relplot()
:
sns.relplot(data=df_iris, x='petal_width', y='petal_length',
hue='species',
palette=dict_color,
kind='scatter')
plt.show()
vemos que el código es prácticamente el mismo, pero ahora configuramos un nuevo parámetro kind=
para especificar el tipo de gráfico.
Ahora, obtengamos varios diagramas de dispersión, uno por cada especie
sns.relplot(data=df_iris, x='petal_width', y='petal_length',
hue='species',
palette=dict_color,
kind='scatter',
# obtendremos un diagrama de dispersion por especie
# organizados por columnas
col='species')
plt.show()
sns.relplot(data=df_iris, x='petal_width', y='petal_length',
hue='species',
palette=dict_color,
kind='scatter',
# obtendremos un diagrama de dispersion por especie
# organizados por filas
row='species')
plt.show()
Podemos utilizar row y col al mismo tiempo. Para ver un ejemplo de ello carguemos un nuevo conjunto de datos
df_tips = sns.load_dataset('tips')
df_tips
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Female | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Male | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | Male | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | Female | No | Thur | Dinner | 2 |
244 rows × 7 columns
sns.relplot(data=df_tips, x='total_bill', y='tip',
kind='scatter',
# hora del dia (almuerzo o cena)
row='time',
# estado del fumador
col='smoker')
plt.show()
Con lo cual conseguimos un subgráfico para cada combinación de las variables categóricas time
y smoker
. Como otro ejemplo, podemos ver los diagramas de dispersión de total_bill
versus tip
para cada día de la semana
sns.relplot(data=df_tips, x='total_bill', y='tip',
kind='scatter',
# hora del dia (almuerzo o cena)
col='day')
plt.show()
Puede parecer que los gráficos anteriores están demasiado juntos. Así, podemos configurar el número de subgráficos por fila:
sns.relplot(data=df_tips, x='total_bill', y='tip',
kind='scatter',
# hora del dia (almuerzo o cena)
col='day',
# configuramos 2 graficos por fila
col_wrap=2)
plt.show()
Y podemos cambiar el orden en que se muestran los gráficos
sns.relplot(data=df_tips, x='total_bill', y='tip',
kind='scatter',
# hora del dia (almuerzo o cena)
col='day',
# configuramos 2 graficos por fila
col_wrap=2,
# cambiamos el orden en el que se muestran
# los graficos
col_order=['Sun', 'Sat', 'Fri', 'Thur'])
plt.show()
Ahora veremos algunos aspectos en los cuales modificaremos las visualizaciones de nuestros gráficos.
Aumentaremos el tamaño de los puntos del diagrama de dispersión con base en los valores de la columna size
df_tips.head()
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
sns.relplot(data=df_tips, x='total_bill', y='tip',
# aumentamos el tamagnio de los puntos
# con base en la columna size
size='size',
kind='scatter')
plt.show()
Dado a que los puntos son del mismo color puede hacerse un poco difícil realizar alguna interpretación, por ello configuraremos el color de los puntos de acuerdo a la columna size
sns.relplot(data=df_tips, x='total_bill', y='tip',
# aumentamos el tamagnio de los puntos
# con base en la columna size
size='size',
# configuramos el color de acuerdo a la columna
# size
hue='size',
kind='scatter')
plt.show()
con lo que conseguimos un gráfico más estético y que nos brinda mayor información.
Luego, en vez de utilizar el color y el tamaño como distintivo de las distintas categorías, podemos utilizar el color y el tipo de punto:
sns.relplot(data=df_tips, x='total_bill', y='tip',
# cambiamos el tipo de puntos
# con base en la columna smoker
style='smoker',
# configuramos el color de acuerdo a la columna
# smoker
hue='smoker',
kind='scatter')
plt.show()
Finalmente, podemos configurar la transparencia de los puntos
sns.relplot(data=df_tips, x='total_bill', y='tip',
# cambiamos el tipo de puntos
# con base en la columna smoker
style='smoker',
# configuramos el color de acuerdo a la columna
# smoker
hue='smoker',
# haremos mas transparentes los puntos
alpha=0.4,
# y podemos cambiar los colores como habiamos visto
# antes
palette={'Yes': 'red', 'No': 'blue'},
kind='scatter')
plt.show()
Este tipo de gráficos son muy útiles y usados en series de tiempo, o básicamente en datos que dependen del tiempo.
Para los siguientes ejemplos cargaremos datos sobre los precios históricos de las acciones de Apple, para lo cual utilizaremos la librería yfinance
. Dicha librería obtiene información sobre los principales mercados financieros del mundo y extrae la información proveniente de yahoo finance. Así
# Importacione necesaria
import yfinance as yf
# Accedemos a la informacion de apple con la funcion Ticker()
# donde dentro de dicha funcion colocamos la clave de apple
apple = yf.Ticker('aapl')
# Extraemos la informacion de los precios diarios (interval='1d')
# del 2016-01-01 al 2021-05-10 y reseteamos el indice por defecto.
# Cabe resaltar que lo que obtenemos de la funcion history() es
# un dataframe
df_apple = apple.history(interval='1d', start='2016-01-01', end='2021-05-10').reset_index()
df_apple.head()
Date | Open | High | Low | Close | Volume | Dividends | Stock Splits | |
---|---|---|---|---|---|---|---|---|
0 | 2016-01-04 | 23.484390 | 24.116072 | 23.344779 | 24.111494 | 270597600 | 0.0 | 0.0 |
1 | 2016-01-05 | 24.203049 | 24.225935 | 23.438622 | 23.507282 | 223164000 | 0.0 | 0.0 |
2 | 2016-01-06 | 23.015209 | 23.429466 | 22.857290 | 23.047251 | 273829600 | 0.0 | 0.0 |
3 | 2016-01-07 | 22.584929 | 22.916790 | 22.069970 | 22.074547 | 324377600 | 0.0 | 0.0 |
4 | 2016-01-08 | 22.555181 | 22.683348 | 22.145503 | 22.191277 | 283192000 | 0.0 | 0.0 |
# volvemos a resetear el indice
df_apple = df_apple.reset_index()
df_apple.head()
index | Date | Open | High | Low | Close | Volume | Dividends | Stock Splits | |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | 24.116072 | 23.344779 | 24.111494 | 270597600 | 0.0 | 0.0 |
1 | 1 | 2016-01-05 | 24.203049 | 24.225935 | 23.438622 | 23.507282 | 223164000 | 0.0 | 0.0 |
2 | 2 | 2016-01-06 | 23.015209 | 23.429466 | 22.857290 | 23.047251 | 273829600 | 0.0 | 0.0 |
3 | 3 | 2016-01-07 | 22.584929 | 22.916790 | 22.069970 | 22.074547 | 324377600 | 0.0 | 0.0 |
4 | 4 | 2016-01-08 | 22.555181 | 22.683348 | 22.145503 | 22.191277 | 283192000 | 0.0 | 0.0 |
Podemos realizar un gráfico de dispersión del tiempo (el cual representaremos mediante la columna index
) versus la columna Open
(precio de apertura de las acciones de Apple):
sns.relplot(data=df_apple, x='index', y='Open',
kind='scatter')
plt.show()
Si bien se describe el comportamiento general de las variables en cuestión, como se dijo antes, los gráficos de líneas permite una mejor visualización para datos que dependen del tiempo. Crearemos entonces un gráfico de líneas:
sns.relplot(data=df_apple, x='index', y='Open',
# cambiamos ahora a kind='line'
kind='line')
plt.show()
Con lo cual obtenemos nuestro gráfico de líneas que representa de mejor manera el comportamiento de nuestros datos.
Para continuar con un ejemplo, primero modificaremos el dataframe de los precios de Apple
# Por simplicidad solo nos quedaremos con las siguientes columnas
df_apple = df_apple[['index', 'Date', 'Open']]
df_apple.head()
index | Date | Open | |
---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 |
1 | 1 | 2016-01-05 | 24.203049 |
2 | 2 | 2016-01-06 | 23.015209 |
3 | 3 | 2016-01-07 | 22.584929 |
4 | 4 | 2016-01-08 | 22.555181 |
Luego, extraeremos ahora información sobre más compañias y modificaremos dichos dataframes para que queden de la misma forma que el dataframe anterior. Para ello, para mayor facilidad crearemos una función:
def info_acciones(clave):
# accedemos a la informacion de la compañia dependiendo
# de la clave
comp = yf.Ticker(clave)
# Extraemos la informacion de los precios diarios (interval='1d')
# del 2016-01-01 al 2021-05-10 y reseteamos el indice por defecto.
# Cabe resaltar que lo que obtenemos de la funcion history() es
# un dataframe
df = comp.history(interval='1d', start='2016-01-01', end='2021-05-10').reset_index()
# volvemos a resetear el indice
df = df.reset_index()
# Por simplicidad solo nos quedaremos con las siguientes columnas
df = df[['index', 'Date', 'Open']]
# Retornamos el dataframe anterior
return df
Ahora obtendremos los precios de las acciones de Google, Tesla y Microsoft (puedes ver las claves o símbolos de dichas compañias, y de más compañias, yendo al siguiente Link)
df_google = info_acciones('goog')
df_tesla = info_acciones('tsla')
df_microsoft = info_acciones('msft')
display(df_google.head(2))
display(df_tesla.head(2))
display(df_microsoft.head(2))
index | Date | Open | |
---|---|---|---|
0 | 0 | 2016-01-04 | 37.150002 |
1 | 1 | 2016-01-05 | 37.322498 |
index | Date | Open | |
---|---|---|---|
0 | 0 | 2016-01-04 | 15.381333 |
1 | 1 | 2016-01-05 | 15.090667 |
index | Date | Open | |
---|---|---|---|
0 | 0 | 2016-01-04 | 48.700350 |
1 | 1 | 2016-01-05 | 49.247247 |
Luego, para cada dataframe correspondiente a las 4 compañias con las que estamos trabajando, agregaremos una columna nueva:
# El nombre de la columna nueva para cada dataframe debe ser el mismo
df_apple['Compañia'] = ['Apple' for i in range(df_apple.shape[0])]
df_google['Compañia'] = ['Google' for i in range(df_apple.shape[0])]
df_tesla['Compañia'] = ['Tesla' for i in range(df_apple.shape[0])]
df_microsoft['Compañia'] = ['Microsoft' for i in range(df_apple.shape[0])]
# veamos el dataframe de apple
df_apple.head()
index | Date | Open | Compañia | |
---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | Apple |
1 | 1 | 2016-01-05 | 24.203049 | Apple |
2 | 2 | 2016-01-06 | 23.015209 | Apple |
3 | 3 | 2016-01-07 | 22.584929 | Apple |
4 | 4 | 2016-01-08 | 22.555181 | Apple |
Finalmente, aplicaremos los 4 dataframes en uno solo utilizando la función pd.concat()
import pandas as pd
df_gral = pd.concat([df_apple, df_google, df_tesla, df_microsoft])
df_gral.head()
index | Date | Open | Compañia | |
---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | Apple |
1 | 1 | 2016-01-05 | 24.203049 | Apple |
2 | 2 | 2016-01-06 | 23.015209 | Apple |
3 | 3 | 2016-01-07 | 22.584929 | Apple |
4 | 4 | 2016-01-08 | 22.555181 | Apple |
Resetearemos el índice y sólo nos quedaremos con las mismas cuatro columnas anteriores
df_gral = df_gral.reset_index()[['index', 'Date', 'Open', 'Compañia']]
df_gral.head()
index | Date | Open | Compañia | |
---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | Apple |
1 | 1 | 2016-01-05 | 24.203049 | Apple |
2 | 2 | 2016-01-06 | 23.015209 | Apple |
3 | 3 | 2016-01-07 | 22.584929 | Apple |
4 | 4 | 2016-01-08 | 22.555181 | Apple |
# Vemos que tenemos 1346 registros por cada compañia
df_gral.value_counts('Compañia')
Compañia Apple 1346 Google 1346 Microsoft 1346 Tesla 1346 dtype: int64
# los nombres de las columna
df_gral.columns
Index(['index', 'Date', 'Open', 'Compañia'], dtype='object')
# cambiamos el nombre de la columna index por id
df_gral = df_gral.rename(columns={'index': 'id'})
# veamos que tenemos 4 valores para cada id
df_gral[df_gral.id == 0]
id | Date | Open | Compañia | |
---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | Apple |
1346 | 0 | 2016-01-04 | 37.150002 | |
2692 | 0 | 2016-01-04 | 15.381333 | Tesla |
4038 | 0 | 2016-01-04 | 48.700350 | Microsoft |
Ahora bien, podemos realizar un gráfico de líneas por cada compañia, pero para ello configuraremos los parámetros de hue
y style
como hemos visto en ejemplos anteriores
sns.relplot(data=df_gral, x='id', y='Open',
# configuracion de acuerdo a la columna
# Compañia
style='Compañia',
hue='Compañia',
kind='line')
plt.show()
Podemos configurar markers=True
para observar los puntos del diagrama de dispersión correspondiente, junto con los diagramas de líneas:
sns.relplot(data=df_gral, x='id', y='Open',
# configuracion de acuerdo a la columna
# Compañia
style='Compañia',
hue='Compañia',
# mostramos los puntos
markers=True,
kind='line')
plt.show()
donde el estilo de los puntos varía de acuerdo a cada subgrupo.
Si no queremos visualizar los distintos tipos de líneas configuramos
sns.relplot(data=df_gral, x='id', y='Open',
# configuracion de acuerdo a la columna
# Compañia
style='Compañia',
hue='Compañia',
# mostramos los puntos
markers=True,
# configuramos para que no se vean los
# estilos de lineas
dashes=False,
kind='line')
plt.show()
Por otro lado, recordemos que para cada id tenemos 4 valores asignados
# veamos que tenemos 4 valores para cada id
df_gral[df_gral.id == 0]
id | Date | Open | Compañia | |
---|---|---|---|---|
0 | 0 | 2016-01-04 | 23.484390 | Apple |
1346 | 0 | 2016-01-04 | 37.150002 | |
2692 | 0 | 2016-01-04 | 15.381333 | Tesla |
4038 | 0 | 2016-01-04 | 48.700350 | Microsoft |
# veamos que tenemos 4 valores para cada id
df_gral[df_gral.id == 1]
id | Date | Open | Compañia | |
---|---|---|---|---|
1 | 1 | 2016-01-05 | 24.203049 | Apple |
1347 | 1 | 2016-01-05 | 37.322498 | |
2693 | 1 | 2016-01-05 | 15.090667 | Tesla |
4039 | 1 | 2016-01-05 | 49.247247 | Microsoft |
Podemos realizar un gráfico de líneas para las columnas id
y Open
, pero ahora cada id tiene asignados 4 valores posibles. En ejemplo anteriores cada, digamos, id tenía asociados un único valor.
Antes de realizar el gráfico de líneas que mencionamos antes, veamos su gráfico de dispersión
sns.relplot(data=df_gral, x='id', y='Open',
kind='scatter')
plt.show()
Por otro lado, al graficar el gráfico de líneas lo que ocurrirá es que los distintos valores de Open
para un mismo id
serán agregados a una sola medida, por defecto dicha medida será el promedio. Así
sns.relplot(data=df_gral, x='id', y='Open',
kind='line')
plt.show()
donde vemos que el gráfico de líneas que visualizamos corresponde a los precios promedios de las acciones de las 4 compañias, y además se grafica de manera automática un intervalo de confianza para la media.
Podemos configurar que el área sombreada represente la desviación estándar en vez de los intervalos de confianza:
sns.relplot(data=df_gral, x='id', y='Open',
ci='sd',
kind='line')
plt.show()
Y también podemos desactivar la visualización del intervalo de confianza
sns.relplot(data=df_gral, x='id', y='Open',
ci=None,
kind='line')
plt.show()