✏️ 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