Open In Colab

8. Introduzione a Seaborn#

Nel capitolo precedente abbiamo introdotto Matplotlib. La libreria Seaborn è un complemento di Matplotlib e consente di generare in maniera molto semplice varie visualizzazioni dei dati utili per la data science. Per un approfondimento, rimando ai tutorial sulla pagina web di Seaborn. Presento qui alcuni esempi.

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
import arviz as az
from scipy.constants import golden
import warnings

warnings.filterwarnings("ignore")
warnings.simplefilter("ignore")
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
# Initialize random number generator
RANDOM_SEED = 8927
rng = np.random.default_rng(RANDOM_SEED)

plt.style.use("bmh")
plt.rcParams["figure.figsize"] = [10, 6]
plt.rcParams["figure.dpi"] = 100
plt.rcParams["figure.facecolor"] = "white"

sns.set_theme(
    context="paper",
    palette="colorblind",
)

%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = "svg"

Considero nuovamente i dati Palmer penguin.

df = pd.read_csv("data/penguins.csv")

8.1. Visualizzare la distribuzione dei dati#

Una delle rappresentazioni grafiche dei dati che si usano più spesso è l’istogramma, o l’istogramma lisciato. Come in precedenza, possiamo creare un istogramma o un kde plot direttamente da pandas:

df["body_mass_g"].plot.hist()
<Axes: ylabel='Frequency'>
_images/f240188ec2bd75f0527300be21d0faf84dd775415c8dc04afb8529cd6cbea317.svg
df["body_mass_g"].plot.kde(bw_method=0.3)
<Axes: ylabel='Density'>
_images/836dbee12d53f040939bc795ddd5ed915311965b47ad524f00fd31f3eeec061a.svg

Oppure possiamo usare Seaborn:

_ = sns.displot(df, x="body_mass_g")
_images/e8dbf0a5c493d1e543419a435bef822c4874776606c303b6a74924cb5b602858.svg
_ = sns.displot(df, x="body_mass_g", stat="density")
_images/5903baa3e05de60d725ea673885bcc87499cb99955970a6c30f69205c294384c.svg
_ = sns.displot(df, x="body_mass_g", kind="kde")
_images/8ae30ecf4c3516a50d47eabcb075d03fed8b04beacffc90c78fa610395df151a.svg

Creaiamo l’istogramma lisciato di body_massg in funzione di species:

_ = sns.displot(
    df, x="body_mass_g", hue="species", kind="kde"
)
_images/b2999ef215e2163ad1338db65572a0cc1c1f8de6d65d03d7cef35965486ce8c4.svg

8.2. Visualizzazione di dati categoriali#

Consideriamo ora il caso in cui si vuole rappresentare la relazione tra una variabile numerica e una variabile categoriale.

_ = sns.catplot(data=df, x="island", y="bill_length_mm")
_images/6d393e154606f76e635ac714e480909465cc4d503cfeed00a31799bcccc0c79d.svg

Scopriamo che

  • Adelie vive in tutte e tre le isole.

  • Gentoo vive solo in Biscoe.

  • Gentoo e Chinstrap hanno becchi più lunghi rispetto ad Adelie.

Analizziamo ora la massa del corpo in funzione della specie, distinguendo le osservazioni in base al genere. Creaiamo il grafico con dei boxplot.

_ = sns.catplot(
    df, x="species", y="body_mass_g", hue="sex", kind="box"
)
_images/e69c9c6a9efd77a524829d4f7fae62d5e55e4e0853d31174afe5dd492f77bb6a.svg

Dal diagramma è evidente che i pinguini maschi pesano più delle femmine in tutte le specie e che i pinguini Gentoo pesano più di quelli Adelie e Chinstrap.

In alternativa, possiamo usare la rappresentazione del violinplot.

_ = sns.catplot(
    df, x="species", y="body_mass_g", hue="sex", kind="violin"
)
_images/2938b52278d96cfc23944fd8cd08900243358711a3cb4739c723fe59b041e83c.svg
_ = sns.catplot(
    df,
    x="species",
    y="body_mass_g",
    hue="sex",
    kind="violin",
    split=True,
)
_images/e198bf62c401c3e86a293a6d8fdb6dafba03bcf47677cdd82543ec0adf37c55f.svg

8.3. Relazioni tra variabili#

Calcoliamo la correlazione tra le variabili.

vars = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]
corr_matrix = df[vars].corr().round(2)
corr_matrix
bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
bill_length_mm 1.00 -0.24 0.66 0.60
bill_depth_mm -0.24 1.00 -0.58 -0.47
flipper_length_mm 0.66 -0.58 1.00 0.87
body_mass_g 0.60 -0.47 0.87 1.00

È più semplice leggere queste informazioni usando la rappresentazione seguente.

sns.heatmap(corr_matrix, annot=True, linecolor="white", linewidths=5, cmap="YlGnBu")
<Axes: >
_images/47e61d319c706df355bf1ded40ac71c136170221ba99c46f0363eccdfea0516c.svg

La lunghezza della pinna e la massa corporea sono fortemente associati con una correlazione di 0.87. In altre parole, i pinguini con pinne più lunghe generalmente pesano di più.

Vediamo qui sotto un esempio di diagramma a dispersione.

_ = sns.scatterplot(df, x="bill_length_mm", y="bill_depth_mm", hue="species")
_images/3d176aca8a739e2fdb0449ec19b17eaf278949edb621727d9c0ccba19b5c616a.svg

Chiaramente le osservazioni delle tre specie si raggruppano in cluster separati. Per ciascuna specie, la lunghezza e la largezza del becco rientrano in un certo intervallo.

È utile creare grafici separati in base a qualche dimensione dei dati; nell’esempio qui sotto, in base all’isola:

g = sns.relplot(
    data=df,
    x="bill_length_mm",
    y="bill_depth_mm",
    hue="species",
    row="sex",
    col="island",
    height=3,
    facet_kws=dict(margin_titles=True),
)
g.set_axis_labels(
    "Bill length (mm)",
    "Bill depth (mm)",
)
plt.tight_layout()
_images/61414370d989b1a51bab209846b08237b8c8ab425629a813a7167c1651b97160.svg

8.4. Watermark#

%load_ext watermark
%watermark -n -u -v -iv 
Last updated: Sat Jun 17 2023

Python implementation: CPython
Python version       : 3.11.3
IPython version      : 8.12.0

arviz     : 0.15.1
matplotlib: 3.7.1
pandas    : 1.5.3
seaborn   : 0.12.2
numpy     : 1.24.3