✏️ Esercizi#

import numpy as np
RANDOM_SEED = 8927
rng = np.random.default_rng(RANDOM_SEED)

Una Misura della Perdita di Informazione#

La Divergenza di Kullback-Leibler (\(\mathbb{KL}\)), conosciuta anche come entropia relativa, funge da misura quantitativa della perdita di informazione che si verifica quando una distribuzione di probabilità complessa o sconosciuta, denominata \(p\), viene approssimata con una distribuzione più semplice, chiamata \(q\). Questa misura ci fornisce una valutazione di quanto le due distribuzioni differiscano l’una dall’altra in termini informativi. Dal punto di vista matematico, la \(\mathbb{KL}\) si calcola sommando le differenze tra le probabilità logaritmiche associate ad ogni evento possibile secondo \(p\) e \(q\), ponderate per le probabilità degli eventi secondo \(p\). La formula generale è:

\[ \mathbb{KL}(p \parallel q) = \sum_{i=1}^n p_i (\log p_i - \log q_i), \]

dove \(i\) indica ciascun possibile evento all’interno delle distribuzioni. Questo calcolo produce una misura della «distanza» media tra \(p\) e \(q\), considerando le loro probabilità logaritmiche.

Un Esempio Empirico#

Per comprendere meglio questi concetti, esaminiamo ora un esempio numerico, dove definiremo due distribuzioni di probabilità discrete, \(p\) e \(q\).

p = np.array([0.2, 0.5, 0.3])
q = np.array([0.1, 0.2, 0.7])

Calcoliamo l’entropia di \(p\).

h_p = -np.sum(p * np.log(p))
print("Entropia di p: ", h_p)
Entropia di p:  1.0296530140645737

Calcoliamo l’entropia incrociata tra \(p\) e \(q\).

h_pq = -np.sum(p * np.log(q))
print("Entropia incrociata tra p e q: ", h_pq)
Entropia incrociata tra p e q:  1.372238457997479

Calcoliamo la divergenza di Kullback-Leibler da \(p\) a \(q\).

kl_pq = h_pq - h_p
print("Divergenza KL da p a q: ", kl_pq)
Divergenza KL da p a q:  0.34258544393290524

Lo stesso risultato si ottiene applicando la formula della Divergenza \(\mathbb{KL}\).

np.sum(p * (np.log(p) - np.log(q)))
0.3425854439329054

Se invece \(q\) è molto simile a \(p\), la differenza \(\mathbb{KL}\) è molto minore.

p = np.array([0.2, 0.5, 0.3])
q = np.array([0.2, 0.55, 0.25])
np.sum(p * (np.log(p) - np.log(q)))
0.007041377136023895

Consideriamo un secondo esempio. Sia \(p\) una distribuzione binomiale di parametri \(\theta = 0.2\) e \(n = 5\).

# Define the parameters
n = 4
p = 0.2

# Compute the probability mass function
true_py = stats.binom.pmf(range(n + 1), n, p)
print(true_py)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[9], line 6
      3 p = 0.2
      5 # Compute the probability mass function
----> 6 true_py = stats.binom.pmf(range(n + 1), n, p)
      7 print(true_py)

NameError: name 'stats' is not defined

Sia \(q_1\) una approssimazione a \(p\):

q1 = np.array([0.46, 0.42, 0.10, 0.01, 0.01])
print(q1)
[0.46 0.42 0.1  0.01 0.01]

Sia \(q_2\) una distribuzione uniforme:

q2 = [0.2] * 5
print(q2)
[0.2, 0.2, 0.2, 0.2, 0.2]

La divergenza \(\mathbb{KL}\) di \(q_1\) da \(p\) è

kl_pq1 = np.sum(true_py * (np.log(true_py) - np.log(q1)))
print("Divergenza KL di q1 da p: ", kl_pq1)
Divergenza KL di q1 da p:  0.02925199033345882

La divergenza \(\mathbb{KL}\) di \(q_2\) da \(p\) è:

kl_pq2 = np.sum(true_py * (np.log(true_py) - np.log(q2)))
print("Divergenza KL di q2 da p: ", kl_pq2)
Divergenza KL di q2 da p:  0.48635777871415425

È chiaro che perdiamo una quantità maggiore di informazioni se, per descrivere la distribuzione binomiale \(p\), usiamo la distribuzione uniforme \(q_2\) anziché \(q_1\).

La Divergenza Dipende dalla Direzione#

La Divergenza \(\mathbb{KL}\) è spesso paragonata a una «distanza» tra due distribuzioni di probabilità, ma è fondamentale capire che non è simmetrica. Questo significa che la misura di quanto \(p\) è diversa da \(q\) non è la stessa di quanto \(q\) è diversa da \(p\). Questa asimmetria riflette la differenza nella perdita di informazione quando si sostituisce una distribuzione con l’altra.

Per comprendere meglio la Divergenza \(\mathbb{KL}\), è utile considerare l’entropia e l’entropia incrociata. Facciamo un esempio numerico.

# Definire le distribuzioni p e q
p = np.array([0.01, 0.99])
q = np.array([0.7, 0.3])

# Calcolo dell'entropia di p
h_p = -np.sum(p * np.log(p))

# Calcolo dell'entropia incrociata da p a q
h_pq = -np.sum(p * np.log(q))

# Calcolo della divergenza KL da p a q
kl_pq = h_pq - h_p

# Calcolo dell'entropia di q
h_q = -np.sum(q * np.log(q))

# Calcolo dell'entropia incrociata da q a p
h_qp = -np.sum(q * np.log(p))

# Calcolo della divergenza KL da q a p
kl_qp = h_qp - h_q

print(f"Entropia di p: {h_p}")
print(f"Entropia incrociata da p a q: {h_pq}")
print(f"Divergenza KL da p a q: {kl_pq}")

print(f"\nEntropia di q: {h_q}")
print(f"Entropia incrociata da q a p: {h_qp}")
print(f"Divergenza KL da q a p: {kl_qp}")
Entropia di p: 0.056001534354847345
Entropia incrociata da p a q: 1.1954998257220641
Divergenza KL da p a q: 1.1394982913672167

Entropia di q: 0.6108643020548935
Entropia incrociata da q a p: 3.226634230947714
Divergenza KL da q a p: 2.6157699288928207
  • Entropia di \(p\) (\(h(p)\)): Misura l’incertezza o la variabilità all’interno della distribuzione vera \(p\). Nel nostro esempio, l’entropia di \(p\) è 0.056.

  • Entropia Incrociata da \(p\) a \(q\) (\(h(p, q)\)): Misura l’incertezza quando si usa \(q\) per rappresentare \(p\). Nel nostro esempio, è 1.195.

La Divergenza \(\mathbb{KL}\) da \(p\) a \(q\) si calcola come la differenza tra l’entropia incrociata e l’entropia di \(p\), che nel nostro caso è 1.139. Questo valore indica la perdita di informazione quando si utilizza \(q\) per approssimare \(p\).

Quando invertiamo le distribuzioni e calcoliamo la Divergenza \(\mathbb{KL}\) da \(q\) a \(p\), otteniamo un risultato diverso. L’entropia di \(q\) è 0.611 e l’entropia incrociata da \(q\) a \(p\) è 3.227. La Divergenza \(\mathbb{KL}\) risultante da \(q\) a \(p\) è 2.616, molto più grande rispetto a quella da \(p\) a \(q\).

Questi risultati dimostrano chiaramente che la Divergenza \(\mathbb{KL}\) è asimmetrica. La quantità di informazione che si perde nel sostituire \(p\) con \(q\) non è la stessa che si perde sostituendo \(q\) con \(p\). Questa asimmetria è una caratteristica cruciale della Divergenza \(\mathbb{KL}\) e sottolinea l’importanza di considerare attentamente quale distribuzione si sta utilizzando come approssimazione dell’altra.

Informazioni sull’Ambiente di Sviluppo#

%load_ext watermark
%watermark -n -u -v -iv -w
The watermark extension is already loaded. To reload it, use:
  %reload_ext watermark
Last updated: Wed Apr 24 2024

Python implementation: CPython
Python version       : 3.12.2
IPython version      : 8.22.2

numpy      : 1.26.4
pandas     : 2.2.2
statsmodels: 0.14.1
matplotlib : 3.8.4
pymc       : 5.13.0
arviz      : 0.18.0
seaborn    : 0.13.2
scipy      : 1.13.0

Watermark: 2.4.3