✏️ Esercizi#

Probabilità condizionata#

Seguendo il metodo descritto nel libro «Think Bayes» di , per affrontare gli esercizi sulla probabilità condizionata, utilizzeremo una definizione di probabilità semplice e intuitiva, basata sul conteggio degli elementi di un insieme. In particolare, considereremo la probabilità come la frazione di elementi che soddisfano un certo criterio rispetto al totale degli elementi dell’insieme.

Immaginiamo di avere un insieme finito di elementi e di volere calcolare la probabilità di un evento all’interno di questo insieme. Per farlo, contiamo quanti elementi soddisfano il criterio dell’evento e dividiamo questo numero per il totale degli elementi dell’insieme. Questo approccio semplifica notevolmente il calcolo delle probabilità e rende più chiaro come funzionano i concetti di base.

Questa definizione intuitiva di probabilità ci aiuterà ad affrontare gli esercizi e applicare i concetti finora descritti a situazioni concrete e reali.

Preparazione del Notebook#

import numpy as np
import pandas as pd
import random 

Esercizi di ricapitolazione con Python#

Considereremo qui il dataset penguins inteso come un insieme finito sul quale definire vari eventi. Iniziamo ad importare i dati ed escludiamo i dati mancanti.

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

df.dropna(inplace=True)
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 333 entries, 0 to 343
Data columns (total 8 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   species            333 non-null    object 
 1   island             333 non-null    object 
 2   bill_length_mm     333 non-null    float64
 3   bill_depth_mm      333 non-null    float64
 4   flipper_length_mm  333 non-null    float64
 5   body_mass_g        333 non-null    float64
 6   sex                333 non-null    object 
 7   year               333 non-null    int64  
dtypes: float64(4), int64(1), object(3)
memory usage: 23.4+ KB

Ora, poniamoci la domanda se ciascun pinguino viva o meno sull’isola Dream. Per fare ciò, useremo una funzione che ci restituirà un oggetto Pandas Series contenente valori booleani. In particolare, ogni valore sarà True se il pinguino associato vive sull’isola Dream, altrimenti sarà False. In questo modo, avremo un elenco di valori che ci indicheranno per ciascun pinguino se vive o meno sull’isola Dream, utilizzando la potenza di Pandas per effettuare rapidamente questo tipo di calcoli.

on_dream = df["island"] == "Dream"
on_dream.head()
0    False
1    False
2    False
4    False
5    False
Name: island, dtype: bool

Essendo che il valore True corrisponde a 1 e il valore False corrisponde a 0, possiamo utilizzare la funzione .sum() per contare il numero di pinguini che vivono sull’isola Dream. In altre parole, sommando tutti i valori True nell’oggetto Pandas Series ottenuto prima, otterremo il numero totale di pinguini che vivono sull’isola Dream nel nostro campione di dati. Con questa operazione scopriamo che ci sono 123 pinguini che sono stati osservati sull’isola Dream.

on_dream.sum()
123

Per ottenere la proporzione di pinguini che vivono sull’isola Dream, dobbiamo calcolare la frequenza assoluta dei pinguini sull’isola Dream e dividere questo valore per il numero totale di pinguini del nostro campione di dati. Possiamo calcolare questo valore utilizzando il metodo .mean() applicato all’oggetto Pandas Series contenente i valori booleani True e False, ottenuto in precedenza. Questo metodo calcola la media aritmetica di tutti i valori nella serie, dove il valore True viene considerato come 1 e il valore False come 0. In questo modo, il risultato finale ci darà la proporzione di pinguini che vivono sull’isola Dream rispetto al totale dei pinguini del nostro campione di dati.

on_dream.mean()
0.36936936936936937

Circa il 36.9% di tutti i pinguini del nostro campione di dati vivono sull’isola Dream. Questo significa che, se scegliamo un pinguino a caso da questo insieme, la probabilità che viva sull’isola Dream è del 36.9%, ovvero 0.369.

Per automatizzare il calcolo della probabilità, possiamo inserire il codice precedente in una funzione. Questa funzione prenderà in input un oggetto Pandas Series contenente valori booleani, rappresentanti la presenza o meno di un certo attributo, e calcolerà la probabilità come la media aritmetica di tutti i valori nella serie, dove il valore True viene considerato come 1 e il valore False come 0. In questo modo, la funzione calcolerà la proporzione di True rispetto al totale dei valori nella serie e restituirà il valore corrispondente alla probabilità cercata.

def prob(A):
    """Computes the probability of a proposition, A."""
    return A.mean()

Verifichiamo.

prob(on_dream)
0.36936936936936937

Troviamo ora la probabilità che un pinguino sia di genere femminile.

female = df["sex"] == "female"
prob(female)
0.4954954954954955

Intersezione di eventi (congiunzione)#

L’intersezione tra due insiemi corrisponde all’operazione logica della congiunzione. In altre parole, date due proposizioni \(p\) e \(q\), la loro congiunzione è vera solo se entrambe sono vere. Se abbiamo due oggetti Pandas Series contenenti valori booleani, possiamo utilizzare l’operatore & per trovare la loro congiunzione. Questo operatore restituisce un nuovo oggetto Series in cui i valori sono True solo se entrambi i corrispondenti valori nelle due serie sono True.

Definiamo ora un nuovo evento, chiamato «small», che identifica i pinguini la cui massa corporea è inferiore al quantile di ordine 1/3. In altre parole, consideriamo la distribuzione dei pesi dei pinguini nel nostro campione di dati e identifichiamo i pinguini il cui peso è inferiore al valore corrispondente al quantile di ordine 1/3 della distribuzione. Questo evento è rappresentato da un oggetto Pandas Series booleano, in cui i valori sono True se il peso del pinguino è inferiore al quantile di ordine 1/3 e False altrimenti.

small = df["body_mass_g"] < df["body_mass_g"].quantile(1 / 3)
prob(small)
0.30930930930930933

Calcoliamo ora la probabilità che un pinguino sia di sesso femminile e, allo stesso tempo, appartenga alla categoria «small». In altre parole, vogliamo calcolare la probabilità che si verifichino contemporaneamente due eventi: che un pinguino sia di sesso femminile e che appartenga alla categoria «small».

prob(female & small)
0.2552552552552553

Come ci possiamo aspettare la probabilità dell’intersezione è minore della probabilità di «small» dato che non tutti i pinguini più piccoli sono di genere femminile.

Probabilità condizionata#

Come abbiamo visto in precedenza, la probabilità condizionata è la probabilità calcolata su un sottoinsieme di eventi. Per selezionare un sottoinsieme di dati in un oggetto Pandas, utilizziamo la notazione delle parentesi quadre. Nell’istruzione seguente, selezioniamo solo i pinguini di sesso femminile tra quelli che appartengono alla categoria «small», ovvero quelli il cui peso corporeo è inferiore al quantile di ordine 1/3.

selected = female[small]
prob(selected)
0.8252427184466019

È importante notare la sintassi utilizzata in questo passaggio: quando inseriamo un oggetto Series booleano (in questo caso chiamato small) tra le parentesi quadre che seguono un oggetto Series (in questo caso chiamato female), stiamo selezionando solo le righe di female per le quali small ha il valore True.

Definiamo ora una funzione che prende in input due oggetti Series booleani, proposition e given, e restituisce la probabilità condizionata di proposition rispetto a given. In altre parole, la funzione calcola la probabilità che proposition si verifichi, sapendo che given si è verificato.

def conditional(proposition, given):
    return prob(proposition[given])

Calcoliamo ora la probabilità condizionata che un pinguino sia di sesso femminile, dato che appartiene alla categoria «small», ovvero il sottoinsieme di pinguini il cui peso corporeo è inferiore al quantile di ordine 1/3.

conditional(female, given=small)
0.8252427184466019

Troviamo ora la probabilità di essere di genere femminile, se consideriamo solo i pinguini sull’isola Dream, \(P(\text{female} \mid \text{Dream})\).

conditional(female, given=on_dream)
0.4959349593495935

Lo stesso risultato si ottiene applicando la definizione di probabilità condizionata.

prob(female & on_dream) / prob(on_dream)
0.49593495934959353

Calcoliamo la probabilità di estrarre a caso un pinguino di sesso femminile che vive sull’isola Dream.

prob(female & on_dream) 
0.1831831831831832

Possiamo ottenere lo stesso risultato del calcolo precedente, ovvero la probabilità di estrarre a caso un pinguino di sesso femminile che vive sull’isola Dream, usando la probabilità condizionata per calcolare l’intersezione tra i due eventi.

conditional(female, given=on_dream) * prob(on_dream)
0.18318318318318316