4. Visualització de dades amb Matplotlib i Seaborn
Matplotlib i Seaborn¶
Matplotlib i Seaborn són dues llibreries de visualització de dades molt populars en el món de la programació en Python, sobretot en el camp de visualització de dades.
- Matplotlib:
- Què és: Matplotlib és una llibreria de visualització de dades en 2D que permet crear gràfics de línia, barres, histogrames, gràfics de dispersió, entre d'altres.
- Característiques:
- És una llibreria molt utilitzada i reconeguda per la seva flexibilitat.
- Permet un control detallat sobre cada element del gràfic.
- Pot ser utilitzat per a gràfics senzills o per a gràfics completament personalitzats.
import matplotlib.pyplot as plt
# Dades
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
# Crear un gràfic de línia
plt.plot(x, y)
# Mostrar el gràfic
plt.show()
- Seaborn:
- Què és: Seaborn és una llibreria de visualització de dades construïda sobre Matplotlib que simplifica la creació de gràfics i els fa estèticament més agradables. Està dissenyada específicament per a l'anàlisi de dades estadístiques.
- Característiques:
- Proporciona funcions d'alt nivell per a tasques comunes de visualització estadística.
- Ofereix paletes de colors atractives i estils de gràfic predefinits.
- Es pot utilitzar per a gràfics complexos amb poques línies de codi.
import seaborn as sns
import matplotlib.pyplot as plt
# Dades
x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
# Configurar el tema de Seaborn
sns.set_theme()
# Crear un gràfic de línia amb Seaborn
sns.lineplot(x=x, y=y)
# Mostrar el gràfic
plt.show()
Ens centrarem més en la part de Seaborn.
Vegem un altre exemple senzill amb dades reals:
import pandas as pd
fifa_filepath = "data/fifa.csv"
# Read the file into a variable fifa_data
fifa_data = pd.read_csv(fifa_filepath, index_col="Date", parse_dates=True)
# Set the width and height of the figure
plt.figure(figsize=(16,8))
# Line chart showing how FIFA rankings evolved over time
sns.lineplot(data=fifa_data)
<Axes: xlabel='Date'>
Gràfics de línies¶
Un "line chart" o gràfic de línia és un tipus comú de visualització de dades que connecta punts de dades successius amb segments de línia recta. Aquest tipus de gràfic és útil per mostrar la relació i la continuïtat entre les dades en una seqüència ordenada, com podrien ser les dades en una sèrie temporal.
Anem a utilitzar un datadet que conté les reproduccions diàries de les cinc cançons més escoltades de Spotify els anys 2017 i 2018.
# Path of the file to read
spotify_filepath = "data/spotify.csv"
# Read the file into a variable spotify_data
spotify_data = pd.read_csv(spotify_filepath, index_col="Date", parse_dates=True)
spotify_data.head()
| Shape of You | Despacito | Something Just Like This | HUMBLE. | Unforgettable | |
|---|---|---|---|---|---|
| Date | |||||
| 2017-01-06 | 12287078 | NaN | NaN | NaN | NaN |
| 2017-01-07 | 13190270 | NaN | NaN | NaN | NaN |
| 2017-01-08 | 13099919 | NaN | NaN | NaN | NaN |
| 2017-01-09 | 14506351 | NaN | NaN | NaN | NaN |
| 2017-01-10 | 14275628 | NaN | NaN | NaN | NaN |
Com podem observar, la cançó "Shape of you" és la que primer es va llançar, per això no tenim dades de la resta en eixes dates.
spotify_data.tail()
| Shape of You | Despacito | Something Just Like This | HUMBLE. | Unforgettable | |
|---|---|---|---|---|---|
| Date | |||||
| 2018-01-05 | 4492978 | 3450315.0 | 2408365.0 | 2685857.0 | 2869783.0 |
| 2018-01-06 | 4416476 | 3394284.0 | 2188035.0 | 2559044.0 | 2743748.0 |
| 2018-01-07 | 4009104 | 3020789.0 | 1908129.0 | 2350985.0 | 2441045.0 |
| 2018-01-08 | 4135505 | 2755266.0 | 2023251.0 | 2523265.0 | 2622693.0 |
| 2018-01-09 | 4168506 | 2791601.0 | 2058016.0 | 2727678.0 | 2627334.0 |
Com podem observar, una vegada llançades, les cançons acumulen milions de reproduccions cada dia.
Procedim a representar les dades en un gràfic de línies
# Line chart showing daily global streams of each song
sns.lineplot(data=spotify_data)
<Axes: xlabel='Date'>
De vegades hi ha detalls addicionals que volem modificar, com les dimensions de la figura i el títol del gràfic. Cadascuna d'aquestes opcions es pot configurar.
# Set the width and height of the figure
plt.figure(figsize=(14,6))
# Add title
plt.title("Daily Global Streams of Popular Songs in 2017-2018")
# Line chart showing daily global streams of each song
sns.lineplot(data=spotify_data)
<Axes: title={'center': 'Daily Global Streams of Popular Songs in 2017-2018'}, xlabel='Date'>
Si el que ens interessa representar no és tot el conjunt de dades, sinó simplement un subconjunt, ho podem fer de la següent forma:
print(list(spotify_data.columns))
['Shape of You', 'Despacito', 'Something Just Like This', 'HUMBLE.', 'Unforgettable']
plt.figure(figsize=(14,6))
# Add title
plt.title("Daily Global Streams of Popular Songs in 2017-2018")
# Line chart showing daily global streams of 'Shape of You'
sns.lineplot(data=spotify_data['Shape of You'], label="Shape of You")
# Line chart showing daily global streams of 'Despacito'
sns.lineplot(data=spotify_data['Despacito'], label="Despacito")
# Add label for horizontal axis
plt.xlabel("Date")
plt.ylabel("Daily Global Streams")
Text(0, 0.5, 'Daily Global Streams')
Si ens interessa filtrar un rang temporal, ho podem fer utilitzant el après anteriorment amb pandas.
df_december = spotify_data.loc['2017-12-01':'2017-12-31']
plt.figure(figsize=(14,6))
# Add title
plt.title("Daily Global Streams of Popular Songs in 2017-2018")
# Line chart showing daily global streams of 'Shape of You'
sns.lineplot(data=df_december['Shape of You'], label="Shape of You")
# Line chart showing daily global streams of 'Despacito'
sns.lineplot(data=df_december['Despacito'], label="Despacito")
# Add label for horizontal axis
plt.xlabel("Date")
plt.ylabel("Daily Global Streams")
Text(0, 0.5, 'Daily Global Streams')
Gràfics de barres¶
Un "bar chart" o gràfic de barres és una representació visual de dades que utilitza rectangles verticals o horitzontals per mostrar comparacions entre categories. Cada barra representa una categoria, i la longitud o altura de la barra indica la magnitud de la variable que està sent mesurada. Són útils per comparar ràpidament valors entre diferents categories.
Un exemple senzill d'un gràfic de barres utilitzant Seaborn seria el següent:
import seaborn as sns
import matplotlib.pyplot as plt
# Exemple de dades
categories = ['Categoria A', 'Categoria B', 'Categoria C', 'Categoria D']
values = [25, 40, 30, 20]
# Crear un gràfic de barres amb Seaborn
sns.barplot(x=categories, y=values, palette="viridis")
# Etiquetes i títol
plt.xlabel('Categories')
plt.ylabel('Valors')
plt.title('Gràfic de Barres amb Seaborn')
# Mostrar el gràfic
plt.show()
/tmp/ipykernel_12574/2717844670.py:9: FutureWarning: Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect. sns.barplot(x=categories, y=values, palette="viridis")
Heatmaps¶
Un "heatmap" o mapa de calor és una visualització de dades en forma de matriu on els valors individuals estan representats com a colors. Aquest tipus de gràfic és particularment útil per mostrar relacions i patrons en dades bidimensionals, com ara matrius de correlació, dades de temperatura, o altres conjunts de dades on hi ha una dependència entre dues variables.
Les cel·les de la matriu s'omplin amb colors segons els valors que representen, creant una representació visual ràpida i intuïtiva de la distribució de les dades. En un heatmap típic, els colors poden anar des de tons freds fins a tons calents, indicant valors baixos a alts.
Este tipus de gràfic és molt utilitzat per veure quines són les variables més correlacionades, és a dir, les que més influixen per a determinar una predicció.
Ací tens un exemple senzill d'un heatmap utilitzant la llibreria Seaborn en Python:
import seaborn as sns
import matplotlib.pyplot as plt
# Exemple de dades en una matriu
data = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]]
# Crear un heatmap amb Seaborn
sns.heatmap(data, annot=True, cmap='magma')
# Etiquetes i títol
plt.xlabel('Columnes')
plt.ylabel('Files')
plt.title('Heatmap amb Seaborn')
# Mostrar el heatmap
plt.show()
Scatterplot¶
Un "scatter plot" o gràfic de dispersió és un tipus de visualització que mostra la relació entre dues variables mitjançant punts en un pla de coordenades cartesianes. Cada punt en el gràfic representa una observació i té coordenades (x, y) corresponents als valors de dues variables. El scatter plot és útil per identificar patrons de dispersió, correlació o agrupació en les dades. Si recordeu, l'utilitzarem en la pràctica de KNN de l'apartat anterior per veure els veíns més pròxims per fer agrupacions.
Per a mostrar un exemple de gràfic de dispersió, aquesta vegada utilitzarem un DataSet real de preus d'assegurances.
import pandas as pd
# Path of the file to read
insurance_filepath = "data/insurance.csv"
# Read the file into a variable insurance_data
insurance_data = pd.read_csv(insurance_filepath)
insurance_data.head()
| age | sex | bmi | children | smoker | region | charges | |
|---|---|---|---|---|---|---|---|
| 0 | 19 | female | 27.900 | 0 | yes | southwest | 16884.92400 |
| 1 | 18 | male | 33.770 | 1 | no | southeast | 1725.55230 |
| 2 | 28 | male | 33.000 | 3 | no | southeast | 4449.46200 |
| 3 | 33 | male | 22.705 | 0 | no | northwest | 21984.47061 |
| 4 | 32 | male | 28.880 | 0 | no | northwest | 3866.85520 |
Anem a representar l'índex de massa corporal front al preu de l'assegurança:
sns.scatterplot(x=insurance_data['bmi'], y=insurance_data['charges'])
<Axes: xlabel='bmi', ylabel='charges'>
Si observem la disperssió, podem deduir que a major bmi, més es paga. És a dir, estan positivament correlacionades les dues variables.
Per veure la seua correlació, podem pintar la recta de regressió, que és dels algorismes més senzills per a fer prediccions. Es tracta de la recta mitja que més s'aproxima als punts.
sns.regplot(x=insurance_data['bmi'], y=insurance_data['charges'])
<Axes: xlabel='bmi', ylabel='charges'>
Gràfics de dispersió codificats amb colors¶
Podem utilitzar gràfics de dispersió per mostrar la relació entre tres variables. Una manera de fer-ho és codificant els punts amb colors.
Per exemple, per entendre com el tabaquisme afecta la relació entre l'IMC i els costos de l'assegurança, podem codificar els punts per colors per "smoker" i traçar les altres dues columnes (bmi, charges) als eixos.
sns.scatterplot(x=insurance_data['bmi'], y=insurance_data['charges'], hue=insurance_data['smoker'])
<Axes: xlabel='bmi', ylabel='charges'>
Aquest gràfic de dispersió mostra que, mentre que els no fumadors tendeixen a pagar una mica més amb l'augment de l'IMC, els fumadors paguen MOLT més.
Per emfatitzar encara més aquest fet, podem utilitzar l'ordre sns.lmplot per afegir dues línies de regressió, corresponents a fumadors i no fumadors. Notaràs que la línia de regressió per als fumadors té un pendent molt més pronunciat, en relació amb la línia per als no fumadors.
sns.lmplot(x="bmi", y="charges", hue="smoker", data=insurance_data)
<seaborn.axisgrid.FacetGrid at 0x7fc333fab6d0>
Finalment, hi ha un tipus de gràfic més que pot ser interessant estudiar. És lleugerament diferent de com esteu acostumats a veure els diagrames de dispersió. Normalment, fem servir gràfics de dispersió per destacar la relació entre dues variables contínues (com bmi i charges). Tanmateix, podem adaptar el disseny del diagrama de dispersió per incloure una variable categòrica (com smoker) en un dels eixos principals. Ens referirem a aquest tipus de gràfic com a gràfic de dispersió categòric i el construïm amb l'ordre sns.swarmplot.
sns.swarmplot(x=insurance_data['smoker'], y=insurance_data['charges'])
/home/ferran/.local/lib/python3.11/site-packages/seaborn/categorical.py:3370: UserWarning: 37.4% of the points cannot be placed; you may want to decrease the size of the markers or use stripplot. warnings.warn(msg, UserWarning)
<Axes: xlabel='smoker', ylabel='charges'>
/home/ferran/.local/lib/python3.11/site-packages/seaborn/categorical.py:3370: UserWarning: 60.8% of the points cannot be placed; you may want to decrease the size of the markers or use stripplot. warnings.warn(msg, UserWarning)
Distribucions¶
En aquest apartat treballarem amb distribucions, histogrames i gràfics de densitat.
Treballarem amb un conjunt de dades de 150 flors diferents, o 50 cadascuna de tres espècies diferents d'iris (Iris setosa, Iris versicolor i Iris virginica).

# Path of the file to read
iris_filepath = "data/iris.csv"
# Read the file into a variable iris_data
iris_data = pd.read_csv(iris_filepath, index_col="Id")
# Print the first 5 rows of the data
iris_data.head()
| Sepal Length (cm) | Sepal Width (cm) | Petal Length (cm) | Petal Width (cm) | Species | |
|---|---|---|---|---|---|
| Id | |||||
| 1 | 5.1 | 3.5 | 1.4 | 0.2 | Iris-setosa |
| 2 | 4.9 | 3.0 | 1.4 | 0.2 | Iris-setosa |
| 3 | 4.7 | 3.2 | 1.3 | 0.2 | Iris-setosa |
| 4 | 4.6 | 3.1 | 1.5 | 0.2 | Iris-setosa |
| 5 | 5.0 | 3.6 | 1.4 | 0.2 | Iris-setosa |
Histogrames¶
Un histograma és una representació gràfica de la distribució de les dades en un conjunt. Aquest tipus de gràfic divideix l'eix de les x en intervals o "bins" i compta quantes vegades les dades cauen dins de cada interval. Les altures de les barres en l'histograma indiquen la freqüència o la densitat de les dades en cada interval.
L'histograma és especialment útil per visualitzar la forma de la distribució i identificar tendències, patrons o característiques importants en les dades.
Per poder veure com varia la longitud dels pètals a les flors de l'iris. Ho podem amb un histograma, ordre sns.histplot.
# Histogram
sns.histplot(iris_data['Petal Length (cm)'])
<Axes: xlabel='Petal Length (cm)', ylabel='Count'>
Gràfics de densitat¶
Un gràfic de densitat és una representació gràfica de la distribució de probabilitat d'un conjunt de dades contínues. Aquest tipus de gràfic proporciona una estimació visual de la funció de densitat de probabilitat de les dades, mostrant com es distribueixen les observacions al llarg de l'eix de les x.
Diferent d'un histograma, que divideix les dades en intervals (bins) i compta quantes observacions hi ha en cada interval, un gràfic de densitat utilitza una funció matemàtica per estimar la distribució contínua de les dades. El gràfic de densitat pot ser útil quan es vol tenir una representació suavitzada de la distribució sense la necessitat d'utilitzar bins discrets.
En aquest tipus de gràfic, la suma total de l'àrea sota la corba de densitat és igual a 1, ja que reflecteix la probabilitat total. Així, es pot interpretar visualment quina proporció de les dades cau en determinades àrees de la distribució.
Podeu pensar que és com la versió contínua d'un histograma.
Utilitza el kernel density estimate (KDE) per mostrar la funció de probabilitat de la variable a representar.
sns.kdeplot(data=iris_data['Petal Length (cm)'], fill=True)
<Axes: xlabel='Petal Length (cm)', ylabel='Density'>
Gràfics de densitat 2D¶
No estem restringits a una sola columna quan creem un gràfic de dispersió. Podem crear un diagrama KDE bidimensional (2D) amb l'ordre sns.jointplot.
Al següent gràfic, la codificació de colors ens mostra la probabilitat que tenim de veure diferents combinacions d'amplada de sèpal i longitud de pètals. Les parts més fosques són més probables.
sns.jointplot(x=iris_data['Petal Length (cm)'], y=iris_data['Sepal Width (cm)'], kind="kde")
<seaborn.axisgrid.JointGrid at 0x7fc33143b9d0>
Tingueu en compte que al centre:
- la corba de la part superior de la figura és una gràfica de KDE per a les dades de l'eix x (en aquest cas, iris_data['Longitud del pètal (cm)']), i
- la corba de la dreta de la figura és una gràfica de KDE per a les dades de l'eix y (en aquest cas, iris_data['Sepal Width (cm)']).
Gràfics codificades per colors¶
Anem a veure si representant les diferents espècies en diferent color podem veure algun patró de comportament, tal qual faria un algorisme d'intel·ligència artificial.
Podem crear tres histogrames diferents (un per a cada espècie) de longitud de pètals mitjançant l'ordre sns.histplot (com abans).
# Histograms for each species
sns.histplot(data=iris_data, x='Petal Length (cm)', hue='Species')
# Add title
plt.title("Histogram of Petal Lengths, by Species")
Text(0.5, 1.0, 'Histogram of Petal Lengths, by Species')
També podem crear un gràfic de dispersió per a cada espècie utilitzant sns.kdeplot.
# KDE plots for each species
sns.kdeplot(data=iris_data, x='Petal Length (cm)', hue='Species', fill=True)
# Add title
plt.title("Distribution of Petal Lengths, by Species")
Text(0.5, 1.0, 'Distribution of Petal Lengths, by Species')
De l'anterior gràfic podriem traure algunes conclusions:
- si la longitud dels pètals d'una flor de l'iris és inferior a 2 cm, el més probable és que sigui Iris setosa.
- si està per dalt de 6 el més probable és que siga iris-virginica
- si està entre 2,5 i 4 el més probable és que siga iris-versicolor
- si la longitud està entre 4 i 5, no podriem determinar quina és l'espècie més probable, necessitariem afegir variables i enytrenar un model.
Subplots¶
Podem crear diversos gràfics simultàniament amb subplots.
# Crear subplots amb 1 fila i 2 columnes
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 6))
# Subplot 1: Scatter Plot
sns.scatterplot(x="Sepal Length (cm)", y="Sepal Width (cm)", hue="Species", data=iris_data, ax=axes[0])
axes[0].set_title('Scatter Plot - Longitud del Sépal vs Amplada del Sépal')
# Subplot 2: Box Plot
sns.boxplot(x="Species", y="Petal Length (cm)", data=iris_data, ax=axes[1])
axes[1].set_title('Box Plot - Longitud del Pètal per Espècie')
# Ajustaments globals
plt.tight_layout()
plt.show()
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
fig.suptitle('Pokemon Stats by Generation')
# Subplot 1: Scatter Plot
sns.scatterplot(x="Sepal Length (cm)", y="Sepal Width (cm)", hue="Species", data=iris_data, ax=axes[0, 0])
axes[0, 0].set_title('Scatter Plot - Longitud del Sépal vs Amplada del Sépal')
# Subplot 2: Box Plot
sns.boxplot(x="Species", y="Petal Length (cm)", data=iris_data, ax=axes[1, 0])
axes[1, 0].set_title('Box Plot - Longitud del Pètal per Espècie')
# Subplot 3: KDE plot
sns.kdeplot(data=iris_data, x='Petal Length (cm)', hue='Species', fill=True, ax=axes[0, 1])
axes[0,1].set_title("Distribution of Petal Lengths, by Species")
# Subplot 4: Histogram
sns.histplot(data=iris_data, x='Petal Length (cm)', hue='Species', ax=axes[1,1])
axes[1,1].set_title("Histogram of Petal Lengths, by Species")
# Ajustaments globals
plt.tight_layout()
plt.show()
Si volem subplots que no ocupen el mateix espai ho podem fer amb el mètode add_subplot de la següent forma:
figure=plt.figure()
axes = figure.add_subplot(2,2,1)
axes = figure.add_subplot(2,2,3)
axes = figure.add_subplot(1,2,2)
figure=plt.figure()
axes1 = figure.add_subplot(2,2,1)
axes2 = figure.add_subplot(2,2,2)
axes3 = figure.add_subplot(2,1,2)
figure=plt.figure()
axes1 = figure.add_subplot(3,2,1)
axes2 = figure.add_subplot(3,2,3)
axes3 = figure.add_subplot(3,2,5)
axes4 = figure.add_subplot(2,2,2)
axes5 = figure.add_subplot(2,2,4)