✏️ Esercizi#

import pandas as pd
import numpy as np
from scipy import stats
import arviz as az
import pingouin as pg
%config InlineBackend.figure_format = 'retina'
RANDOM_SEED = 8927
rng = np.random.default_rng(RANDOM_SEED)
az.style.use("arviz-darkgrid")

Esercizio 1#

Per questo esempio, analizzeremo il file penguins.csv. Dopo aver caricato il dataset, procederemo con l’eliminazione delle righe contenenti dati mancanti e reimposteremo l’indice delle righe.

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

# Drop rows with missing values
df.dropna(inplace=True)

# Reset the index
df.reset_index(drop=True, inplace=True)
df.head()
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 male 2007
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 female 2007
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 female 2007
3 Adelie Torgersen 36.7 19.3 193.0 3450.0 female 2007
4 Adelie Torgersen 39.3 20.6 190.0 3650.0 male 2007
df.describe(include="all")
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
count 333 333 333.000000 333.000000 333.000000 333.000000 333 333.000000
unique 3 3 NaN NaN NaN NaN 2 NaN
top Adelie Biscoe NaN NaN NaN NaN male NaN
freq 146 163 NaN NaN NaN NaN 168 NaN
mean NaN NaN 43.992793 17.164865 200.966967 4207.057057 NaN 2008.042042
std NaN NaN 5.468668 1.969235 14.015765 805.215802 NaN 0.812944
min NaN NaN 32.100000 13.100000 172.000000 2700.000000 NaN 2007.000000
25% NaN NaN 39.500000 15.600000 190.000000 3550.000000 NaN 2007.000000
50% NaN NaN 44.500000 17.300000 197.000000 4050.000000 NaN 2008.000000
75% NaN NaN 48.600000 18.700000 213.000000 4775.000000 NaN 2009.000000
max NaN NaN 59.600000 21.500000 231.000000 6300.000000 NaN 2009.000000

Esaminiamo le modalità delle variabili categoriali.

df["island"].unique()
array(['Torgersen', 'Biscoe', 'Dream'], dtype=object)
df["species"].unique()
array(['Adelie', 'Gentoo', 'Chinstrap'], dtype=object)
df["sex"].unique()
array(['male', 'female'], dtype=object)

Vogliamo calcolare l’intervallo di confidenza al 95% per il peso («body_mass_g») separatamente per i pinguini femmina e maschi sull’isola Biscoe.

female_biscoe = df[(df["island"] == "Biscoe") & (df["sex"] == "female")][
    "body_mass_g"
]
male_biscoe = df[(df["island"] == "Biscoe") & (df["sex"] == "male")]["body_mass_g"]
mean_female_biscoe = np.mean(female_biscoe)
print(mean_female_biscoe)
4319.375
se_female_biscoe = np.std(female_biscoe, ddof=1) / np.sqrt(len(female_biscoe))
print(se_female_biscoe)
73.76216779048659
degrees_freedom = len(female_biscoe) - 1
print(degrees_freedom)
79
alpha = 0.05
t_critical_lower = stats.t.ppf(alpha / 2, degrees_freedom)
t_critical_upper = stats.t.ppf(1 - alpha / 2, degrees_freedom)
print(t_critical_lower, t_critical_upper)
-1.9904502102301287 1.9904502102301282
mean_female_biscoe + np.array([-1, 1]) * t_critical_upper * se_female_biscoe
array([4172.55507761, 4466.19492239])
def calculate_confidence_interval(data, alpha=0.05):
    """
    Calcola l'intervallo di confidenza per la media di un array di dati.

    Parametri:
    data (array-like): Array di dati numerici.
    alpha (float): Livello di significatività per l'intervallo di confidenza (default 0.05).

    Ritorna:
    tuple: intervallo di confidenza (limite inferiore, limite superiore).
    """
    mean = np.mean(data)  # Calcola la media dei dati
    se = np.std(data, ddof=1) / np.sqrt(
        len(data)
    )  # Calcola l'errore standard della media
    df = len(data) - 1  # Calcola i gradi di libertà

    # Trova i valori critici t per alpha/2 e 1-alpha/2
    t_critical_lower = stats.t.ppf(alpha / 2, df)
    t_critical_upper = stats.t.ppf(1 - alpha / 2, df)

    # Calcola l'intervallo di confidenza
    confidence_interval_lower = mean + t_critical_lower * se
    confidence_interval_upper = mean + t_critical_upper * se

    return (confidence_interval_lower, confidence_interval_upper)
calculate_confidence_interval(female_biscoe, alpha = 0.05)
(4172.5550776143955, 4466.194922385604)

Replichiamo il risultato usando ttest.

pg.ttest(female_biscoe, len(female_biscoe)-1)
T dof alternative p-val CI95% cohen-d BF10 power
T-test 57.487126 79 two-sided 3.174629e-66 [4172.56, 4466.19] 6.427256 2.852e+62 1.0

Calcoliamo ora l’intervallo di confidenza per i pinguini maschi.

calculate_confidence_interval(male_biscoe, alpha=0.05)
(4948.568652154555, 5260.467492423758)
pg.ttest(male_biscoe, len(male_biscoe) - 1)
T dof alternative p-val CI95% cohen-d BF10 power
T-test 64.068134 82 two-sided 8.268249e-72 [4948.57, 5260.47] 7.032391 9.622e+67 1.0

Poiché i due intervalli di confidenza non si sovrappongono, possiamo suggerire che esista una differenza tra il peso dei pinguini maschi e quello delle pinguine femmine sull’isola Biscoe, con un livello di confidenza del 95%. Tuttavia, per affermare con certezza la significatività statistica di questa differenza, l’approccio frequentista ritiene appropriato condurre un test di ipotesi specifico.

Esercizio 2#

Consideriamo ora il calcolo dell’intervallo di confidenza per la differenza tra due medie. Assumiamo che i due campioni provengano da due popolazione con la stessa varianza ma con medie diverse.

def confidence_interval_diff_means(sample1, sample2, confidence=0.95):
    # Calcolo delle medie e deviazioni standard dei campioni
    mean1, mean2 = np.mean(sample1), np.mean(sample2)
    std1, std2 = np.std(sample1, ddof=1), np.std(sample2, ddof=1)
    n1, n2 = len(sample1), len(sample2)

    # Calcolo della differenza delle medie e della varianza combinata
    mean_diff = mean1 - mean2

    sigma_hat = np.sqrt(
        ((n1 - 1) * std1**2 + (n2 - 1) * std2**2) / 
        (n1 + n2 - 2)
        )

    se_diff = sigma_hat * np.sqrt((1 / n1) + (1 / n2))

    # Calcolo dei gradi di libertà senza la correzione di Welch
    df = n1 + n2 - 2

    # Determinazione del quantile della distribuzione t per il livello di confidenza desiderato
    t_crit = stats.t.ppf((1 + confidence) / 2, df)

    # Calcolo dell'intervallo di confidenza
    margin_error = t_crit * se_diff
    ci_lower = mean_diff - margin_error
    ci_upper = mean_diff + margin_error

    return ci_lower, ci_upper

Otteniamo l’intervallo di confidenza al 95% per la differenza tra il peso dei pinguini femmine e maschi sull’isola Biscoe:

confidence_interval_diff_means(male_biscoe, female_biscoe, confidence=0.95)
(572.2628806689312, 998.0232639093816)

Poiché l’intervallo di confidenza al 95% per la differenza di peso medio tra i pinguini maschi e femmine sull’isola Biscoe non include lo zero, possiamo concludere che, in media, i pinguini maschi pesano più delle femmine.

Replichiamo il risultato precedente usando la funzione ttest() del pacchetto pingouin.

pg.ttest(male_biscoe, female_biscoe, correction = False)
T dof alternative p-val CI95% cohen-d BF10 power
T-test 7.283472 161 two-sided 1.368366e-11 [572.26, 998.02] 1.141164 5.264e+08 1.0

Se non vogliamo assumere che le varianze delle due popolazioni siano uguali, specifichiamo correction = True come argomento nella funzione pg.ttest().

Esercizio 3#

Consideriamo il calcolo dell’intervallo di confidenza per la differenza tra due proporzioni.

Calcoliamo la proporzione di pinguini femmine che hanno un peso maggiore della media dei pinguini sull’isola Biscoe.

mean_weight_island = np.mean(df[(df["island"] == "Biscoe")]["body_mass_g"])
print(mean_weight_island)
4719.171779141105
success_female = np.sum(female_biscoe > mean_weight_island)
print(success_female)
27
success_male = np.sum(male_biscoe > mean_weight_island)
print(success_male)
63
def confidence_interval_prop_diff(success1, size1, success2, size2, confidence=0.95):
    # Calcolo delle proporzioni
    p1 = success1 / size1
    p2 = success2 / size2

    # Differenza delle proporzioni
    prop_diff = p1 - p2

    # Errore standard della differenza
    se_diff = np.sqrt(p1 * (1 - p1) / size1 + p2 * (1 - p2) / size2)

    # Z-score per il livello di confidenza specificato
    z_score = stats.norm.ppf((1 + confidence) / 2)

    # Margine di errore
    margin_error = z_score * se_diff

    # Calcolo dell'intervallo di confidenza
    ci_lower = prop_diff - margin_error
    ci_upper = prop_diff + margin_error

    return ci_lower, ci_upper
confidence_interval_prop_diff(
    success_male, len(male_biscoe), success_female, len(female_biscoe)
)
(0.28296600258820487, 0.5601062865684217)

In questo caso, l’intervallo di confidenza include il valore 0,5. Pertanto, non possiamo affermare, con un livello di fiducia del 95%, che esista una differenza degna di nota tra le proporzioni osservate nei maschi e nelle femmine.

Informazioni sull’Ambiente di Sviluppo#

%load_ext watermark
%watermark -n -u -v -iv -w -m
Last updated: Sun Jun 16 2024

Python implementation: CPython
Python version       : 3.12.3
IPython version      : 8.25.0

Compiler    : Clang 16.0.6 
OS          : Darwin
Release     : 23.4.0
Machine     : arm64
Processor   : arm
CPU cores   : 8
Architecture: 64bit

scipy   : 1.13.1
numpy   : 1.26.4
pingouin: 0.5.4
pandas  : 2.2.2
arviz   : 0.18.0

Watermark: 2.4.3