[Appendice ] — Entropia]{#sec-solutions-entropia .quarto-section-identifier}

# Standard library imports
import os

# Third-party imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import arviz as az
import scipy.stats as stats
from scipy.special import expit  # Funzione logistica
from cmdstanpy import cmdstan_path, CmdStanModel

# Configuration
seed = sum(map(ord, "stan_poisson_regression"))
rng = np.random.default_rng(seed=seed)
az.style.use("arviz-darkgrid")
%config InlineBackend.figure_format = "retina"

# Define directories
home_directory = os.path.expanduser("~")
project_directory = f"{home_directory}/_repositories/psicometria"

# Print project directory to verify
print(f"Project directory: {project_directory}")
Project directory: /Users/corradocaudek/_repositories/psicometria

Capitolo 97

Esercizio 98.1

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

Esercizio 98.2

# 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)
[0.4096 0.4096 0.1536 0.0256 0.0016]
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]
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\).

Esercizio 98.3

# 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