Introduzione

L’azienda Neonatal Health Solutions vuole sviluppare un modello predittivo del peso del neonato alla nascita a partire da informazioni cliniche raccolte su un campione di 2500 neonati provenienti da tre ospedali. L’obiettivo è identificare le variabili più predittive e fornire stime utili a supportare la gestione clinica e l’allocazione delle risorse ospedaliere.

Analisi preliminare del dataset

Prima di fare inferenza sul dataset e costruire il modello analizzo la struttura del dataset composto dalle seguenti features: - Anni.madre — età della madre in anni
- N.gravidanze — numero di gravidanze pregresse della madre
- Fumatrici — indicatore binario del fumo materno (0 = non fumatrice, 1 = fumatrice)
- Gestazione — durata della gravidanza in settimane
- Peso — peso del neonato alla nascita, in grammi
- Lunghezza — lunghezza del neonato in millimetri (misurabile anche in fase prenatale tramite ecografia)
- Cranio — diametro craniale del neonato in millimetri (anch’esso misurabile via ecografia)
- Tipo.parto — tipologia del parto (Nat = naturale, Ces = cesareo)
- Ospedale — ospedale di nascita (osp1, osp2, osp3)
- Sesso — sesso del neonato (M = maschio, F = femmina)

L’obiettivo principale è identificare quali variabili siano più predittive del peso alla nascita, con un focus particolare su:

glimpse(neonati)
## Rows: 2,500
## Columns: 10
## $ Anni.madre   <dbl> 26, 21, 34, 28, 20, 32, 26, 25, 22, 23, 29, 21, 36, 24, 3…
## $ N.gravidanze <dbl> 0, 2, 3, 1, 0, 0, 1, 0, 1, 0, 2, 2, 5, 0, 3, 2, 2, 3, 0, …
## $ Fumatrici    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ Gestazione   <dbl> 42, 39, 38, 41, 38, 40, 39, 40, 40, 41, 38, 40, 38, 40, 3…
## $ Peso         <dbl> 3380, 3150, 3640, 3690, 3700, 3200, 3100, 3580, 3670, 370…
## $ Lunghezza    <dbl> 490, 490, 500, 515, 480, 495, 480, 510, 500, 510, 480, 51…
## $ Cranio       <dbl> 325, 345, 375, 365, 335, 340, 345, 349, 335, 362, 330, 34…
## $ Tipo.parto   <chr> "Nat", "Nat", "Nat", "Nat", "Nat", "Nat", "Nat", "Nat", "…
## $ Ospedale     <chr> "osp3", "osp1", "osp2", "osp2", "osp3", "osp2", "osp3", "…
## $ Sesso        <chr> "M", "F", "M", "M", "F", "F", "F", "M", "F", "F", "M", "F…
summary(neonati)
##    Anni.madre     N.gravidanze       Fumatrici        Gestazione   
##  Min.   : 0.00   Min.   : 0.0000   Min.   :0.0000   Min.   :25.00  
##  1st Qu.:25.00   1st Qu.: 0.0000   1st Qu.:0.0000   1st Qu.:38.00  
##  Median :28.00   Median : 1.0000   Median :0.0000   Median :39.00  
##  Mean   :28.16   Mean   : 0.9812   Mean   :0.0416   Mean   :38.98  
##  3rd Qu.:32.00   3rd Qu.: 1.0000   3rd Qu.:0.0000   3rd Qu.:40.00  
##  Max.   :46.00   Max.   :12.0000   Max.   :1.0000   Max.   :43.00  
##       Peso        Lunghezza         Cranio        Tipo.parto        Ospedale   
##  Min.   : 830   Min.   :310.0   Min.   :235   Length   :2500   Length   :2500  
##  1st Qu.:2990   1st Qu.:480.0   1st Qu.:330   N.unique :   2   N.unique :   3  
##  Median :3300   Median :500.0   Median :340   N.blank  :   0   N.blank  :   0  
##  Mean   :3284   Mean   :494.7   Mean   :340   Min.nchar:   3   Min.nchar:   4  
##  3rd Qu.:3620   3rd Qu.:510.0   3rd Qu.:350   Max.nchar:   3   Max.nchar:   4  
##  Max.   :4930   Max.   :565.0   Max.   :390                                    
##        Sesso     
##  Length   :2500  
##  N.unique :   2  
##  N.blank  :   0  
##  Min.nchar:   1  
##  Max.nchar:   1  
## 

Dalla prima esplorazione dei dati i valori da osservare e trattare perchè possibili errori nel dataset riguardano età minima della madre (0, quantomeno sospetto) e 12 gravidanze come valore massimo.

sum(neonati$Anni.madre == 0)
## [1] 1
neonati %>% filter(Anni.madre < 14)
## # A tibble: 3 × 10
##   Anni.madre N.gravidanze Fumatrici Gestazione  Peso Lunghezza Cranio Tipo.parto
##        <dbl>        <dbl>     <dbl>      <dbl> <dbl>     <dbl>  <dbl> <chr>     
## 1         13            0         0         38  2760       470    325 Nat       
## 2          1            1         0         41  3250       490    350 Nat       
## 3          0            0         0         39  3060       490    330 Nat       
## # ℹ 2 more variables: Ospedale <chr>, Sesso <chr>

Dei tre casi di gravidanza sotto i 14 anni due sono sicuri errori di battitura( 0 anni e 1 anno), il terzo (13 anni) potrebbe essere plausibile ma visto che non inficia i risultati, avendo gli altri valori non troppo discostati dalla media, lo considero trascurabile come gli altri e rimuovo tutti e tre.

Verifica delle osservazioni con molte gravidanze

Vista la presenza di donne con numero di gravidanze elevato prima di valutare che siano errori di compilazione controllo che le età siano credibili:

neonati %>%
  mutate(ID = row_number()) %>%
  filter(N.gravidanze >= 8) %>%
  arrange(desc(N.gravidanze)) %>%
  select(ID, everything()) %>%
  kable(caption = "Osservazioni con N.gravidanze elevato") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Osservazioni con N.gravidanze elevato
ID Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto Ospedale Sesso
1219 38 12 0 39 3350 490 344 Nat osp2 M
1130 33 11 0 43 3400 475 360 Nat osp1 M
2221 35 10 0 39 2950 495 335 Nat osp1 F
2422 33 10 0 40 3090 485 353 Nat osp3 M
2471 34 10 0 38 2880 470 345 Ces osp2 M
161 35 9 0 42 3760 540 348 Nat osp2 F
1781 35 9 0 37 3150 490 335 Nat osp2 M
89 36 8 0 39 3610 500 351 Ces osp1 M
204 30 8 0 40 3850 518 340 Nat osp3 F
516 40 8 0 38 3520 470 341 Nat osp3 M
1450 36 8 0 41 3730 480 335 Nat osp3 M
1505 30 8 0 39 2860 490 337 Ces osp2 F
1727 36 8 0 36 2860 460 334 Nat osp2 F
2086 26 8 0 40 3250 500 355 Nat osp2 M
2175 37 8 0 28 930 355 235 Nat osp1 F

Delle 15 osservazioni con almeno 8 gravidanze tutte le età o quasi sono plausibili(fascia 30-38 anni) seppur in contesti socio-culturali particolari. Il caso limite che potrebbe tranquillamente essere errore di data entry è l’id 2086, madre di 26 anni all’ottava gravidanza il che presupporrebbe dall’inizio dell’età fertile una gravidanza ogni circa 15 mesi senza soste. Raro ma senza evidenze contrarie che possano permettere una rimozione dal dataset. Altro caso particolare l’id 2175, madre con gravidanza con gestazione minima del dataset (28 settimane) e valori fisici del bambino ovviamente compatibili con una nascita prematura.

Pulizia finale e preparazione del dataset

Sulla base di quanto riportato applico le modifiche al dataset:

  • Aggiungo una colonna ID con il numero di riga originale, per poter fare riferimento a singole osservazioni nel commento dei risultati successivi.
  • Rimuovo le tre osservazioni con età madre < 14 anni (sicuri errori di data entry).
  • Converto le variabili categoriche (Tipo.parto, Ospedale, Sesso, Fumatrici) in factor, tipo nativo di R per le variabili qualitative, necessario per la corretta gestione nei test inferenziali e nei modelli di regressione.
neonati <- neonati %>%
  mutate(ID = row_number()) %>%
  filter(Anni.madre >= 14) %>%
  mutate(
    Tipo.parto = factor(Tipo.parto),
    Ospedale   = factor(Ospedale),
    Sesso      = factor(Sesso),
    Fumatrici  = factor(Fumatrici, levels = c(0, 1), labels = c("No", "Sì"))
  )

nrow(neonati)
## [1] 2497

Il dataset pulito risulta composto ora da 2497 osservazioni.

glimpse(neonati)
## Rows: 2,497
## Columns: 11
## $ Anni.madre   <dbl> 26, 21, 34, 28, 20, 32, 26, 25, 22, 23, 29, 21, 36, 24, 3…
## $ N.gravidanze <dbl> 0, 2, 3, 1, 0, 0, 1, 0, 1, 0, 2, 2, 5, 0, 3, 2, 2, 3, 0, …
## $ Fumatrici    <fct> No, No, No, No, No, No, No, No, No, No, No, No, No, No, N…
## $ Gestazione   <dbl> 42, 39, 38, 41, 38, 40, 39, 40, 40, 41, 38, 40, 38, 40, 3…
## $ Peso         <dbl> 3380, 3150, 3640, 3690, 3700, 3200, 3100, 3580, 3670, 370…
## $ Lunghezza    <dbl> 490, 490, 500, 515, 480, 495, 480, 510, 500, 510, 480, 51…
## $ Cranio       <dbl> 325, 345, 375, 365, 335, 340, 345, 349, 335, 362, 330, 34…
## $ Tipo.parto   <fct> Nat, Nat, Nat, Nat, Nat, Nat, Nat, Nat, Ces, Ces, Ces, Na…
## $ Ospedale     <fct> osp3, osp1, osp2, osp2, osp3, osp2, osp3, osp1, osp2, osp…
## $ Sesso        <fct> M, F, M, M, F, F, F, M, F, F, M, F, F, F, M, M, M, M, F, …
## $ ID           <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17…

Analisi descrittiva preliminare

Prima di procedere con i test inferenziali, esploro le caratteristiche del dataset pulito.

Variabili quantitative

describe(neonati[, c("Anni.madre", "N.gravidanze", "Gestazione", 
                     "Peso", "Lunghezza", "Cranio")]) %>%
  kable(digits = 2, caption = "Statistiche descrittive delle variabili numeriche") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(width = "100%")
Statistiche descrittive delle variabili numeriche
vars n mean sd median trimmed mad min max range skew kurtosis se
Anni.madre 1 2497 28.19 5.21 28 28.11 4.45 14 46 32 0.16 -0.12 0.10
N.gravidanze 2 2497 0.98 1.28 1 0.75 1.48 0 12 12 2.51 10.97 0.03
Gestazione 3 2497 38.98 1.87 39 39.18 1.48 25 43 18 -2.06 8.25 0.04
Peso 4 2497 3284.39 525.23 3300 3303.32 459.61 830 4930 4100 -0.65 2.03 10.51
Lunghezza 5 2497 494.71 26.33 500 496.47 22.24 310 565 255 -1.51 6.48 0.53
Cranio 6 2497 340.04 16.43 340 340.69 14.83 235 390 155 -0.79 2.94 0.33

Variabili qualitative

# Tipo di parto
table(neonati$Tipo.parto) %>% 
  as.data.frame() %>%
  rename(Tipo = Var1, Frequenza = Freq) %>%
  mutate(Percentuale = round(Frequenza / sum(Frequenza) * 100, 2)) %>%
  kable(caption = "Distribuzione del tipo di parto") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Distribuzione del tipo di parto
Tipo Frequenza Percentuale
Ces 728 29.15
Nat 1769 70.85
# Ospedale
table(neonati$Ospedale) %>% 
  as.data.frame() %>%
  rename(Ospedale = Var1, Frequenza = Freq) %>%
  mutate(Percentuale = round(Frequenza / sum(Frequenza) * 100, 2)) %>%
  kable(caption = "Distribuzione delle nascite per ospedale") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Distribuzione delle nascite per ospedale
Ospedale Frequenza Percentuale
osp1 816 32.68
osp2 847 33.92
osp3 834 33.40
# Sesso
table(neonati$Sesso) %>% 
  as.data.frame() %>%
  rename(Sesso = Var1, Frequenza = Freq) %>%
  mutate(Percentuale = round(Frequenza / sum(Frequenza) * 100, 2)) %>%
  kable(caption = "Distribuzione per sesso") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Distribuzione per sesso
Sesso Frequenza Percentuale
F 1254 50.22
M 1243 49.78
# Madri fumatrici
table(neonati$Fumatrici) %>% 
  as.data.frame() %>%
  rename(Fumatrice = Var1, Frequenza = Freq) %>%
  mutate(Percentuale = round(Frequenza / sum(Frequenza) * 100, 2)) %>%
  kable(caption = "Distribuzione del fumo materno") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Distribuzione del fumo materno
Fumatrice Frequenza Percentuale
No 2393 95.84
104 4.16

Grafici delle variabili chiave

Le due variabili centrali del progetto sono Peso (variabile risposta del modello di regressione) e Gestazione (predittore principale, indicatore di nascite premature). Verifico graficamente la distribuzione.

ggplot(neonati, aes(x = Peso)) +
  geom_histogram(bins = 40, fill = "steelblue", color = "white") +
  labs(title = "Distribuzione del peso del neonato",
       x = "Peso (grammi)",
       y = "Frequenza") +
  theme_minimal()

ggplot(neonati, aes(x = Gestazione)) +
  geom_histogram(bins = 20, fill = "darkorange", color = "white") +
  labs(title = "Distribuzione della settimana di gestazione",
       x = "Settimane di gestazione",
       y = "Frequenza") +
  theme_minimal()

Commento

Distribuzione del Peso: la variabile risposta del modello mostra una forma approssimativamente gaussiana, simmetrica e centrata attorno ai 3300 grammi. È presente una leggera coda sinistra dovuta ai casi di prematuri estremi (es. ID 2175 identificato in fase di pulizia). Questa forma è favorevole come premessa al metodo: la regressione lineare assume che ad essere normali siano i residui e una variabile risposta già approssimativamente gaussiana costituisce un buon punto di partenza.

Distribuzione della Gestazione: a differenza del Peso, la durata della gestazione mostra una distribuzione fortemente asimmetrica a sinistra, con un picco modale a 40 settimane e una coda di parti prematuri (25-37 settimane). Questa asimmetria è plausibile con i casi clinici reali e non costituisce un problema per il modello di regressione, che come detto richiede normalità dei residui ma non dei predittori.

Verifica delle ipotesi

Ipotesi 1 — Differenza dei parti cesarei tra ospedali

Voglio verificare se la proporzione di parti cesarei differisce significativamente tra i tre ospedali del campione, oppure se le differenze osservate sono attribuibili alla variabilità campionaria.

Formulazione delle ipotesi

  • H₀: Il tipo di parto è indipendente dall’ospedale (le proporzioni di cesarei sono uguali nei tre ospedali)
  • H₁: Il tipo di parto dipende dall’ospedale (almeno un ospedale ha una proporzione diversa)

Tabella di contingenza

tabella_parti <- table(neonati$Tipo.parto, neonati$Ospedale)

addmargins(tabella_parti, FUN = list(Totale = sum), quiet = TRUE) %>%
  kable(caption = "Frequenze osservate: tipo di parto per ospedale") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(3, bold = TRUE, background = "#e8e8e8") %>%
  column_spec(5, bold = TRUE, background = "#e8e8e8")
Frequenze osservate: tipo di parto per ospedale
osp1 osp2 osp3 Totale
Ces 242 254 232 728
Nat 574 593 602 1769
Totale 816 847 834 2497

Per facilitare la lettura, calcolo anche le percentuali di cesarei per ospedale:

prop.table(tabella_parti, margin = 2) %>%
  round(3) %>%
  addmargins(margin = 1,FUN = list(Totale = sum), quiet = TRUE) %>%
  kable(caption = "Proporzioni di tipo di parto per ospedale") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(3, bold = TRUE, background = "#e8e8e8")
Proporzioni di tipo di parto per ospedale
osp1 osp2 osp3
Ces 0.297 0.3 0.278
Nat 0.703 0.7 0.722
Totale 1.000 1.0 1.000

Il parametro margin = 2 calcola le proporzioni per colonna (ospedale): ogni colonna somma a 1, e leggo direttamente la percentuale di cesarei e naturali per ciascun ospedale.

Test del chi quadrato

test_chi <- chisq.test(tabella_parti)
test_chi
## 
##  Pearson's Chi-squared test
## 
## data:  tabella_parti
## X-squared = 1.1062, df = 2, p-value = 0.5752

Frequenze attese sotto H₀

Verifico le frequenze attese (utile sia per controllare la validità del test che per capire dove cadono le maggiori discrepanze):

test_chi$expected %>%
  round(2) %>%
  addmargins(FUN = list(Totale = sum), quiet = TRUE) %>%
  kable(caption = "Frequenze attese sotto l'ipotesi di indipendenza") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  row_spec(3, bold = TRUE, background = "#e8e8e8") %>%
  column_spec(5, bold = TRUE, background = "#e8e8e8")
Frequenze attese sotto l’ipotesi di indipendenza
osp1 osp2 osp3 Totale
Ces 237.9 246.94 243.15 727.99
Nat 578.1 600.06 590.85 1769.01
Totale 816.0 847.00 834.00 2497.00

Conclusione

Il test del chi quadrato ha prodotto i seguenti risultati:

  • Statistica χ² = 1.11
  • Gradi di libertà = 2
  • p-value = 0.575

Con un p-value pari a 0.575, ampiamente superiore alla soglia convenzionale di 0.05, non rifiuto l’ipotesi nulla di indipendenza. I dati non forniscono evidenza statistica sufficiente per affermare che la proporzione di parti cesarei differisca tra i tre ospedali del campione.

Il range di percentuale dei parti cesarei nei tre ospedali è ristretto (27,8-30 %) e compatibile con la variabilità campionaria attesa sotto l’ipotesi di indipendenza tra tipo di parto e ospedale, pertanto la scelta su come far nascere i bambini segue criteri omogenei.

Ipotesi 2 — Confronto medie campionarie vs popolazione

Verifico se le medie campionarie di Peso e Lunghezza sono compatibili con i valori medi della popolazione di riferimento.

Valori di riferimento della popolazione

Da fonti come ISTAT e OMS, i valori medi di riferimento per neonati a termine sono approssimativamente:

  • Peso medio: 3300 grammi
  • Lunghezza media: 500 mm (50 cm)

Non conoscendo la σ di peso e lunghezza della popolazione italiana il test da adottare è il t, con n=2497(campione grande) per il Teorema del Limite Centrale so che la distribuzione campionaria sarà praticamente normale, anche se la popolazione non lo fosse.

Test t per il peso

Formulazione delle ipotesi

  • H₀: μ_peso = 3300 g (la media del campione coincide con quella di popolazione)
  • H₁: μ_peso ≠ 3300 g (le medie differiscono)

Statistiche descrittive del campione

data.frame(
  Statistica = c("n", "Media", "Deviazione standard", "Errore standard"),
  Valore = c(
    nrow(neonati),
    round(mean(neonati$Peso), 2),
    round(sd(neonati$Peso), 2),
    round(sd(neonati$Peso)/sqrt(nrow(neonati)), 2)
  )
) %>%
  kable(caption = "Statistiche descrittive del Peso") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Statistiche descrittive del Peso
Statistica Valore
n 2497.00
Media 3284.39
Deviazione standard 525.23
Errore standard 10.51

Esecuzione del test

test_peso <- t.test(neonati$Peso, mu = 3300)
test_peso
## 
##  One Sample t-test
## 
## data:  neonati$Peso
## t = -1.4847, df = 2496, p-value = 0.1377
## alternative hypothesis: true mean is not equal to 3300
## 95 percent confidence interval:
##  3263.783 3305.005
## sample estimates:
## mean of x 
##  3284.394

Con p-value = 0.1377 > 0.05 non rifiuto l’ipotesi nulla, la media del campione non è statisticamente diversa dal valore di riferimento(3300 g), i grammi di differenza rientrano nella variabilità campionaria. Il valore della media della popolazione(3300 gr) rientra, seppur di poco, nell’ intervallo di confidenza[3263.783 ; 3305.005] a conferma della precedente conclusione.

Test t per la lunghezza

Formulazione delle ipotesi

  • H₀: μ_lunghezza = 500 mm
  • H₁: μ_lunghezza ≠ 500 mm

Statistiche descrittive del campione

data.frame(
  Statistica = c("n", "Media", "Deviazione standard", "Errore standard"),
  Valore = c(
    nrow(neonati),
    round(mean(neonati$Lunghezza), 2),
    round(sd(neonati$Lunghezza), 2),
    round(sd(neonati$Lunghezza)/sqrt(nrow(neonati)), 2)
  )
) %>%
  kable(caption = "Statistiche descrittive della Lunghezza") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Statistiche descrittive della Lunghezza
Statistica Valore
n 2497.00
Media 494.71
Deviazione standard 26.33
Errore standard 0.53

Esecuzione del test

test_lunghezza <- t.test(neonati$Lunghezza, mu = 500)
test_lunghezza
## 
##  One Sample t-test
## 
## data:  neonati$Lunghezza
## t = -10.048, df = 2496, p-value < 0.00000000000000022
## alternative hypothesis: true mean is not equal to 500
## 95 percent confidence interval:
##  493.6724 495.7389
## sample estimates:
## mean of x 
##  494.7056

Il p value risulta virtualmente nullo pertanto rifiuto l’ipotesi nulla con ampia evidenza, l’intervallo di confidenza[493.6724;495.7389] non contiene 500 pertanto c’è una differenza statistica significativa. In questo caso occorre però distinguere tra significatività statistica e rilevanza pratica, seppur sia da scartare l’ipotesi nulla relativamente alla lunghezza dei neonati, i 5 mm di differenza media rilevati (circa 1% della media nazionale) non hanno una valenza clinica e sono trascurabili. La causa può essere dovuta a metodologie di misurazione differenti.

Peso e lunghezza hanno mostrato nel campione differenze in percentuale dalla popolazione molto simili e piccole (0,5% peso e 1% lunghezza). Il fatto che vengano statisticamente trattati diversamente dipende dall’errore standard delle due variabili, nel caso della lunghezza dei neonati essendo molto piccolo (0,53) fa sì che la differenza trovata sia statisticamente estrema (t = -10.048), in altre parole i dati sono più concentrati [493.6724 ; 495.7389] e la differenza risalta di più.

Il campione può quindi ritenersi “rappresentativo della popolazione” anche se dal punto di vista statistico solo nel caso del peso si può accettare l’ipotesi nulla. Il test per la lunghezza come detto è significativo (p < 10⁻¹⁶, IC esclude 500), ma la differenza assoluta è di 5 mm — entro la precisione delle misurazioni cliniche standard. Ai fini operativi il campione può considerarsi buono, in attesa che eventuali approfondimenti metodologici possano spiegare l’origine della discrepanza.

Ipotesi 3 — Differenze antropometriche tra i sessi

In questo caso voglio verificare se le misure( Peso, Lunghezza, Cranio) dei neonati maschi differiscono significativamente da quelle delle neonate femmine. In questo caso il test da applicare sarà a due campioni indipendenti (media vs altra media). I due campioni sono indipendenti dato che un neonato o nasce maschio o nasce femmina, quindi non si misura lo stesso due volte.

Formulazione delle ipotesi

Per ciascuna delle tre variabili antropometriche(Peso, Lunghezza, Cranio) testo:

  • H₀: μ_M = μ_F (le medie nei due sessi sono uguali)
  • H₁: μ_M ≠ μ_F (le medie differiscono)

Statistiche descrittive per sesso

neonati %>%
  group_by(Sesso) %>%
  summarise(
    n = n(),
    media_peso = round(mean(Peso), 2),
    sd_peso = round(sd(Peso), 2),
    media_lunghezza = round(mean(Lunghezza), 2),
    sd_lunghezza = round(sd(Lunghezza), 2),
    media_cranio = round(mean(Cranio), 2),
    sd_cranio = round(sd(Cranio), 2)
  ) %>%
  kable(caption = "Statistiche antropometriche per sesso") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Statistiche antropometriche per sesso
Sesso n media_peso sd_peso media_lunghezza sd_lunghezza media_cranio sd_cranio
F 1254 3161.38 526.6 489.78 27.55 337.63 16.74
M 1243 3408.50 493.9 499.67 24.05 342.46 15.75

Test t per il Peso

test_peso_sesso <- t.test(Peso ~ Sesso, data = neonati)
test_peso_sesso
## 
##  Welch Two Sample t-test
## 
## data:  Peso by Sesso
## t = -12.096, df = 2487.4, p-value < 0.00000000000000022
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
##  -287.1763 -207.0525
## sample estimates:
## mean in group F mean in group M 
##        3161.381        3408.496

Test t per la Lunghezza

test_lung_sesso <- t.test(Lunghezza ~ Sesso, data = neonati)
test_lung_sesso
## 
##  Welch Two Sample t-test
## 
## data:  Lunghezza by Sesso
## t = -9.5638, df = 2455.7, p-value < 0.00000000000000022
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
##  -11.923919  -7.866232
## sample estimates:
## mean in group F mean in group M 
##        489.7799        499.6750

Test t per il diametro Cranio

test_cranio_sesso <- t.test(Cranio ~ Sesso, data = neonati)
test_cranio_sesso
## 
##  Welch Two Sample t-test
## 
## data:  Cranio by Sesso
## t = -7.4188, df = 2488.1, p-value = 0.0000000000001612
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
##  -6.100823 -3.549966
## sample estimates:
## mean in group F mean in group M 
##        337.6332        342.4586

Visualizzazione

Per visualizzare graficamente le differenze, utilizzo i boxplot per ciascuna delle tre misure:

neonati %>%
  pivot_longer(cols = c(Peso, Lunghezza, Cranio),
               names_to = "Misura",
               values_to = "Valore") %>%
  ggplot(aes(x = Sesso, y = Valore)) +
  geom_boxplot(alpha = 0.7) +
  facet_wrap(~ Misura, scales = "free_y") +
  labs(title = "Distribuzione delle misure antropometriche per sesso",
       x = "Sesso", y = "Valore") +
  theme_minimal()

Conclusione

I tre test t per campioni indipendenti hanno prodotto risultati coerenti: in tutte le tre misure antropometriche, le medie tra maschi e femmine differiscono in modo statisticamente significativo (tutti p-value < 10⁻¹³ quindi virtualmente nulli, gli IC escludono lo zero). I maschi presentano sistematicamente valori medi superiori alle femmine:

  • Peso: +247 g (+7.8%)
  • Lunghezza: +10 mm (+2.0%)
  • Cranio: +5 mm (+1.4%)

Questa gerarchia è coerente con la letteratura biologica e pediatrica: la differenza di peso tra i due sessi alla nascita è un fenomeno ampiamente documentato.

A differenza dell’Ipotesi 2, in cui le differenze statistiche risultavano clinicamente trascurabili, in questo caso la differenza di peso ha effettiva rilevanza clinica: i 247 grammi rappresentano circa l’8% del peso medio neonatale e quasi mezza deviazione standard. Le differenze di lunghezza (1 cm) e cranio (0.5 cm), pur statisticamente certe, sono di entità più contenuta ma comunque biologicamente rilevanti.

Implicazione per il modello di regressione: la variabile Sesso rappresenta un predittore importante del peso del neonato e in quanto tale va inclusa nel modello di regressione che andrò a costruire.

Modello di Regressione Lineare Multipla

Dopo aver analizzato le relazioni singole e verificato le ipotesi formulate, procedo alla costruzione del modello statistico per la previsione del Peso neonatale. L’obiettivo è identificare tra le variabili i predittori più significativi e quantificare il loro impatto.

1. Stima del Modello Completo

Nel modello inizialmente inserisco tutte le variabili , comprese quelle categoriche opportunamente convertite in fattori nella fase di pulizia.

modello_completo <- lm(Peso ~ Anni.madre + N.gravidanze + Fumatrici + 
                        Gestazione + Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso, 
                      data = neonati)


summary(modello_completo)
## 
## Call:
## lm(formula = Peso ~ Anni.madre + N.gravidanze + Fumatrici + Gestazione + 
##     Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso, data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1123.22  -181.60   -14.71   161.14  2611.88 
## 
## Coefficients:
##                 Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)   -6735.6079   141.5732 -47.577 < 0.0000000000000002 ***
## Anni.madre        0.7989     1.1489   0.695               0.4869    
## N.gravidanze     11.3829     4.6697   2.438               0.0149 *  
## FumatriciSì     -30.2796    27.5550  -1.099               0.2719    
## Gestazione       32.5766     3.8215   8.524 < 0.0000000000000002 ***
## Lunghezza        10.2921     0.3010  34.198 < 0.0000000000000002 ***
## Cranio           10.4721     0.4264  24.562 < 0.0000000000000002 ***
## Tipo.partoNat    29.6402    12.0939   2.451               0.0143 *  
## Ospedaleosp2    -11.0767    13.4539  -0.823               0.4104    
## Ospedaleosp3     28.2506    13.5082   2.091               0.0366 *  
## SessoM           77.5650    11.1900   6.932     0.00000000000528 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.1 on 2486 degrees of freedom
## Multiple R-squared:  0.7288, Adjusted R-squared:  0.7277 
## F-statistic:   668 on 10 and 2486 DF,  p-value: < 0.00000000000000022

Il primo risultato è il multiple R-squared=0.7288 : significa che le variabili inserite riescono a spiegare quasi il 73% dei motivi per cui il peso di un neonato varia. Il p-value: < 0.00000000000000022 conferma che il modello è statisticamente solidissimo e i risultati non dipendono dal caso.
Residual standard error: 274.1 significa che il modello nel prevedere il peso di un neonato sbaglia 274.1 grammi in difetto o eccesso. Su un peso medio di 3,3 kg un valore trascurabile dal punto di vista clinico.

Guardando nel complesso la tabella nella colonna Pr(>|t|) si trovano i p-value di ogni feature e il numero di asterischi determina se la variabile può considerarsi predittiva della colonna target,il peso del neonato in questo caso.

Per quanto riguarda le variabili predittive trovo, in ordine di significatività: -le variabili “antropometriche”che ovviamente determinano il peso, maggiore è il diametro craniale, la lunghezza e il periodo di gestazione e più peserà il neonato -il sesso come visto nell’ipotesi 3 ha un valore “Estimate” di 77.5650, significa che,a parità di tutte le altre variabili, essere maschio determina mediamente un aumento di 78 grammi di peso. Questo valore risulta inferiore a quello rilevato nel test t dell’ipotesi 3: questo perchè la regressione ‘depura’ l’effetto del sesso da quello delle variabili correlate(i maschi hanno lunghezza e diametro del cranio maggiore) e restituisce il contributo netto.

Un risultato che potrebbe sorprendere è che il fumo materno (p = 0.272) non risulti tra i predittori significativi, nonostante sia una delle variabili di interesse indicate dal progetto. Le cause plausibili sono due:

  • Bassa numerosità: le fumatrici rappresentano solo il 4% del campione (poche osservazioni per stimare con precisione l’effetto, quindi bassa potenza statistica).
  • Effetto di mediazione: in letteratura il fumo materno è associato a nascite premature e a riduzione delle dimensioni fetali. Se il suo effetto sul peso passa principalmente attraverso variabili come Gestazione, Lunghezza e Cranio (già incluse nel modello), l’effetto “residuo diretto” del fumo risulta attenuato.

Analogamente, l’età materna (p = 0.487) e l’ospedale di nascita (significativo solo marginalmente per osp3) sembrano apportare scarso potere predittivo diretto. Queste variabili rischiano di introdurre rumore statistico senza migliorare sostanzialmente il modello.

Per individuare il modello più parsimonioso, nel rispetto del principio di parsimonia, procedo con una selezione algoritmica tramite metodo stepwise. Confronterò due criteri di selezione richiesti dal progetto: l’AIC (Akaike), che penalizza la complessità con un fattore 2 per parametro, e il BIC (Bayes), più severo, che penalizza con un fattore ln(n) per parametro e tende quindi a selezionare modelli più piccoli.

Selezione stepwise: confronto AIC e BIC

Come anticipato applicherò la procedura stepwise con due criteri diversi:

  • L’AIC (Akaike), che penalizza la complessità con un fattore 2 per parametro
  • Il BIC (Bayes), più severo, che penalizza con un fattore ln(2497) ≈ 7.8 per parametro
# AIC
modello_aic <- step(modello_completo, direction = "both", trace = FALSE)

# BIC
modello_bic <- step(modello_completo, direction = "both", 
                    k = log(nrow(neonati)), trace = FALSE)

Modello selezionato con AIC

summary(modello_aic)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + 
##     Tipo.parto + Ospedale + Sesso, data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1113.06  -181.96   -16.63   161.11  2619.53 
## 
## Coefficients:
##                 Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)   -6707.7610   136.0686 -49.297 < 0.0000000000000002 ***
## N.gravidanze     12.3312     4.3357   2.844              0.00449 ** 
## Gestazione       32.0391     3.7932   8.446 < 0.0000000000000002 ***
## Lunghezza        10.3056     0.3007  34.277 < 0.0000000000000002 ***
## Cranio           10.4918     0.4258  24.642 < 0.0000000000000002 ***
## Tipo.partoNat    29.4198    12.0908   2.433              0.01503 *  
## Ospedaleosp2    -10.8685    13.4512  -0.808              0.41917    
## Ospedaleosp3     28.7918    13.4996   2.133              0.03304 *  
## SessoM           77.4519    11.1878   6.923     0.00000000000561 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.1 on 2488 degrees of freedom
## Multiple R-squared:  0.7286, Adjusted R-squared:  0.7277 
## F-statistic: 834.9 on 8 and 2488 DF,  p-value: < 0.00000000000000022

Modello selezionato con BIC

summary(modello_bic)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + 
##     Sesso, data = neonati)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1149.3  -181.0   -15.6   163.7  2639.0 
## 
## Coefficients:
##                Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)  -6681.4708   135.8505 -49.183 < 0.0000000000000002 ***
## N.gravidanze    12.4483     4.3429   2.866              0.00419 ** 
## Gestazione      32.3833     3.8016   8.518 < 0.0000000000000002 ***
## Lunghezza       10.2452     0.3009  34.050 < 0.0000000000000002 ***
## Cranio          10.5406     0.4266  24.710 < 0.0000000000000002 ***
## SessoM          77.9613    11.2147   6.952     0.00000000000459 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.8 on 2491 degrees of freedom
## Multiple R-squared:  0.7269, Adjusted R-squared:  0.7264 
## F-statistic:  1326 on 5 and 2491 DF,  p-value: < 0.00000000000000022

Confronto dei due modelli

data.frame(
  Criterio = c("AIC", "BIC"),
  Num_predittori = c(length(coef(modello_aic)) - 1,
                     length(coef(modello_bic)) - 1),
  AIC = c(round(AIC(modello_aic), 2), round(AIC(modello_bic), 2)),
  BIC = c(round(BIC(modello_aic), 2), round(BIC(modello_bic), 2)),
  R2_adj = c(round(summary(modello_aic)$adj.r.squared, 4),
             round(summary(modello_bic)$adj.r.squared, 4))
) %>%
  kable(caption = "Confronto tra modello AIC e modello BIC") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Confronto tra modello AIC e modello BIC
Criterio Num_predittori AIC BIC R2_adj
AIC 8 35130.22 35188.45 0.7277
BIC 5 35139.81 35180.57 0.7264

Scelta del modello finale

I due criteri hanno selezionato modelli diversi:

  • L’AIC mantiene 8 predittori, includendo Tipo.parto e Ospedale.
  • Il BIC, più severo, ne mantiene 5, eliminando anche Tipo.parto e Ospedale.

N.B. nel conteggio delle variabili va considerato che ogni categorica apporta k-1 colonne dummy dove k è il numero di modalità assunte

Entrambi concordano nell’eliminare Anni.madre e Fumatrici, le variabili meno significative del modello completo.

Il confronto mostra che la capacità predittiva dei due modelli è praticamente identica: l’R² aggiustato passa da 0.7277 (AIC) a 0.7264 (BIC), una differenza dello 0.13% del tutto trascurabile. A fronte di questa equivalenza predittiva, il modello BIC utilizza 3 variabili in meno.

Scelgo il modello BIC come modello finale, per le seguenti ragioni:

  1. Parsimonia: a parità sostanziale di capacità predittiva, il modello più semplice è preferibile (principio di Occam).
  2. Coerenza con l’Ipotesi 1: il test del chi quadrato aveva già dimostrato l’assenza di differenze significative tra ospedali; l’esclusione di Ospedale dal modello è quindi coerente.
  3. Robustezza dei coefficienti: il modello BIC racchiude tutti predittori fortemente significativi (p ≤ 0.004).

Il modello finale è dunque:

\[\text{Peso} = \beta_0 + \beta_1 \text{N.gravidanze} + \beta_2 \text{Gestazione} + \beta_3 \text{Lunghezza} + \beta_4 \text{Cranio} + \beta_5 \text{Sesso} + \varepsilon\]

modello_finale <- modello_bic
summary(modello_finale)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + 
##     Sesso, data = neonati)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1149.3  -181.0   -15.6   163.7  2639.0 
## 
## Coefficients:
##                Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)  -6681.4708   135.8505 -49.183 < 0.0000000000000002 ***
## N.gravidanze    12.4483     4.3429   2.866              0.00419 ** 
## Gestazione      32.3833     3.8016   8.518 < 0.0000000000000002 ***
## Lunghezza       10.2452     0.3009  34.050 < 0.0000000000000002 ***
## Cranio          10.5406     0.4266  24.710 < 0.0000000000000002 ***
## SessoM          77.9613    11.2147   6.952     0.00000000000459 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.8 on 2491 degrees of freedom
## Multiple R-squared:  0.7269, Adjusted R-squared:  0.7264 
## F-statistic:  1326 on 5 and 2491 DF,  p-value: < 0.00000000000000022

Modelli con interazioni ed effetti non lineari

Vado ora a valutare l’eventuale presenza di effetti non lineari e interazioni tra le variabili, partendo dal modello finale selezionato.

Dal punto di vista clinico il feto non cresce in maniera lineare durante la gestazione ma nelle ultime settimane tende a crescere piu rapidamente. Verifico quindi se un termine quadratico legato alla Gestazione possa migliorare il modello.

Effetto non lineare della Gestazione

modello_quad <- lm(Peso ~ N.gravidanze + Gestazione + I(Gestazione^2) + 
                     Lunghezza + Cranio + Sesso, 
                   data = neonati)
summary(modello_quad)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + I(Gestazione^2) + 
##     Lunghezza + Cranio + Sesso, data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1144.00  -181.62   -12.88   165.89  2661.86 
## 
## Coefficients:
##                   Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)     -4647.6512   898.9178  -5.170      0.0000002523343 ***
## N.gravidanze       12.5444     4.3394   2.891              0.00388 ** 
## Gestazione        -81.1695    49.7584  -1.631              0.10296    
## I(Gestazione^2)     1.5160     0.6624   2.289              0.02218 *  
## Lunghezza          10.3500     0.3041  34.035 < 0.0000000000000002 ***
## Cranio             10.6374     0.4283  24.837 < 0.0000000000000002 ***
## SessoM             75.7454    11.2469   6.735      0.0000000000203 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.5 on 2490 degrees of freedom
## Multiple R-squared:  0.7275, Adjusted R-squared:  0.7268 
## F-statistic:  1108 on 6 and 2490 DF,  p-value: < 0.00000000000000022

Confronto il modello con termine quadratico rispetto al modello finale lineare:

anova(modello_finale, modello_quad)
## Analysis of Variance Table
## 
## Model 1: Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso
## Model 2: Peso ~ N.gravidanze + Gestazione + I(Gestazione^2) + Lunghezza + 
##     Cranio + Sesso
##   Res.Df       RSS Df Sum of Sq      F  Pr(>F)  
## 1   2491 188041153                              
## 2   2490 187646385  1    394769 5.2384 0.02218 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Analizzando i risultati appare subito curioso che la variabile Gestazione perda di significatività (p=0.103) e abbia ora Estimate negativa (−81). Questo effetto è dovuto alla compresenza della variabile quadratica Gestazione² che porta alla collinearità che confonde i coefficienti individuali.

Il p-value = 0.022 dice che il termine quadratico migliora il modello anche se marginalmente: R² aggiustato passa da 0.7264 (finale) a 0.7268 (quadratico), un miglioramento dello 0,04%…

Ritorna il dilemma tra lo “statisticamente significativo” e il “praticamente utile”. Vale la pena complicare il modello introducendo collinearità e interpretazione più difficile per uno 0,04% di varianza in più seppur clinicamente sensato?
Scelgo il no come risposta, visto che inoltre il p-value 0.022 della Gestazione^2 non è così forte ma rileva solo per la numerosità campionaria.

Interazione Gestazione × Sesso

Altra ipotesi clinica da verificare è il diverso peso della Gestazione tra neonati maschi e femmine nel computo del peso:

modello_inter <- lm(Peso ~ N.gravidanze + Gestazione + Lunghezza + 
                      Cranio + Sesso + Gestazione:Sesso, 
                    data = neonati)
summary(modello_inter)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + 
##     Sesso + Gestazione:Sesso, data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1144.68  -181.31   -15.16   163.42  2637.57 
## 
## Coefficients:
##                     Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)       -6572.8113   167.1497 -39.323 < 0.0000000000000002 ***
## N.gravidanze         12.4022     4.3429   2.856              0.00433 ** 
## Gestazione           29.5188     4.5872   6.435       0.000000000148 ***
## Lunghezza            10.2491     0.3009  34.062 < 0.0000000000000002 ***
## Cranio               10.5419     0.4265  24.715 < 0.0000000000000002 ***
## SessoM             -183.8641   234.9464  -0.783              0.43395    
## Gestazione:SessoM     6.7094     6.0138   1.116              0.26467    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 274.7 on 2490 degrees of freedom
## Multiple R-squared:  0.727,  Adjusted R-squared:  0.7264 
## F-statistic:  1105 on 6 and 2490 DF,  p-value: < 0.00000000000000022

Confronto con il modello finale:

anova(modello_finale, modello_inter)
## Analysis of Variance Table
## 
## Model 1: Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso
## Model 2: Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso + 
##     Gestazione:Sesso
##   Res.Df       RSS Df Sum of Sq      F Pr(>F)
## 1   2491 188041153                           
## 2   2490 187947200  1     93953 1.2447 0.2647

Con questa ipotesi ho provato a rispondere alla domanda “l’effetto di una settimana di gestazione sul peso è diverso tra maschi e femmine?” La risposta dei dati, stavolta senza dilemmi interpretativi è no: il p-value 0.265 è proprio alto e il coefficiente di interazione (+6.71) non è significativamente diverso da 0. Da notare che anche in questo caso la collinearità rende il coefficiente di SessoM = - 183

Conclusione sull’esplorazione di interazioni e non-linearità

Come richiesto dal progetto, ho valutato due possibili arricchimenti del modello finale:

Effetto non lineare della Gestazione (termine quadratico): il termine I(Gestazione²) risulta statisticamente significativo (p = 0.022), e il test ANOVA conferma un miglioramento dell’adattamento. Tuttavia, l’incremento di capacità predittiva è trascurabile: l’R² aggiustato passa da 0.7264 a 0.7268 (+0.04%). La significatività è in larga parte attribuibile alla numerosità campionaria elevata, che rende rilevabili anche effetti di entità minima. Considerando il principio di parsimonia e l’introduzione di collinearità tra Gestazione e il suo quadrato, decido di non includere il termine quadratico nel modello finale.

Interazione Gestazione × Sesso: il termine di interazione non è statisticamente significativo (p = 0.265), e il test ANOVA non rileva alcun miglioramento del modello. L’effetto della gestazione sul peso è dunque sostanzialmente uguale per maschi e femmine (le pendenze sono parallele). L’interazione viene scartata.

In sintesi, nessuno dei due arricchimenti esplorati apporta un beneficio sostanziale. Il modello lineare a cinque predittori selezionato in precedenza si conferma come modello finale, privilegiando semplicità e interpretabilità senza sacrificare capacità predittiva.

Analisi della qualità del modello

Valuto ora la qualità del modello finale sotto tre aspetti: le metriche di capacità predittiva, l’analisi dei residui (verifica delle assunzioni) e l’individuazione di eventuali valori influenti.

Metriche di capacità predittiva

# R² e R² aggiustato
r2 <- summary(modello_finale)$r.squared
r2_adj <- summary(modello_finale)$adj.r.squared

# RMSE
rmse <- sqrt(mean(residuals(modello_finale)^2))

# MAE (errore assoluto medio, metrica complementare)
mae <- mean(abs(residuals(modello_finale)))

data.frame(
  Metrica = c("R²", "R² aggiustato", "RMSE (g)", "MAE (g)"),
  Valore = c(round(r2, 4), round(r2_adj, 4), round(rmse, 2), round(mae, 2))
) %>%
  kable(caption = "Metriche di qualità del modello finale") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Metriche di qualità del modello finale
Metrica Valore
0.7269
R² aggiustato 0.7264
RMSE (g) 274.4200
MAE (g) 211.0600

Analisi dei residui

La regressione lineare si fonda su quattro assunzioni sui residui: linearità, normalità, omoschedasticità (varianza costante) e indipendenza.
Verifico ognuna di esse con i quattro grafici diagnostici prodotti da R:

par(mfrow = c(2, 2))
plot(modello_finale)

par(mfrow = c(1, 1))

Test di normalità dei residui

Affianco al QQ-plot un test formale. Data la numerosità elevata, utilizzo sia un grafico sia gli indici di forma:

residui <- residuals(modello_finale)

# Istogramma dei residui
ggplot(data.frame(residui), aes(x = residui)) +
  geom_histogram(bins = 40, fill = "steelblue", color = "white") +
  labs(title = "Distribuzione dei residui del modello",
       x = "Residui (grammi)",
       y = "Frequenza") +
  theme_minimal()

# Indici di forma dei residui
data.frame(
  Indice = c("Media", "Deviazione standard", "Skewness", "Curtosi"),
  Valore = c(
    round(mean(residui), 4),
    round(sd(residui), 2),
    round(skewness(residui), 4),
    round(kurtosis(residui), 4)
  )
) %>%
  kable(caption = "Indici di forma dei residui") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Indici di forma dei residui
Indice Valore
Media 0.0000
Deviazione standard 274.4800
Skewness 0.6967
Curtosi 7.1544

Valori influenti

Verifico ora la presenza di osservazioni che influenzano in modo sproporzionato le stime del modello, utilizzando la distanza di Cook.

cook <- cooks.distance(modello_finale)

# Soglia convenzionale: 4/n
soglia_cook <- 4 / nrow(neonati)

# Grafico della distanza di Cook
plot(cook, type = "h", 
     main = "Distanza di Cook per osservazione",
     xlab = "Indice osservazione", 
     ylab = "Distanza di Cook")
abline(h = soglia_cook, col = "red", lty = 2)

cook <- cooks.distance(modello_finale)
soglia_cook <- 4 / nrow(neonati)

# Osservazioni oltre la soglia
n_influenti <- sum(cook > soglia_cook)
n_influenti
## [1] 124
# 5 osservazioni più influenti
neonati %>%
  mutate(cook = cook) %>%
  arrange(desc(cook)) %>%
  head(5) %>%
  select(ID, Gestazione, Peso, Lunghezza, Cranio, Sesso, cook) %>%
  kable(digits = 4, caption = "Osservazioni più influenti (distanza di Cook)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Osservazioni più influenti (distanza di Cook)
ID Gestazione Peso Lunghezza Cranio Sesso cook
1551 38 4370 315 374 F 0.8295
310 28 1560 420 379 F 0.0675
1780 25 900 325 253 F 0.0335
155 36 3610 410 330 M 0.0303
928 28 830 310 254 F 0.0297

Commento sulla qualità del modello

Capacità predittiva: il modello finale spiega il 72.7% della variabilità del peso (R² aggiustato = 0.7264), con un errore tipico di previsione (RMSE) di circa 274 grammi. Su un peso medio di 3284 g, l’errore relativo è dell’ordine dell’8%, un risultato soddisfacente per un modello clinico. Il fatto che il MAE (211 g) sia inferiore all’RMSE (274 g) segnala la presenza di alcuni errori di previsione elevati, concentrati sui casi clinici estremi.

Analisi dei residui: i grafici diagnostici mostrano un modello complessivamente adeguato. - La relazione è sostanzialmente lineare (grafico Residuals vs Fitted). - I residui hanno media nulla e sono ben distribuiti nella parte centrale. - Si osserva tuttavia una coda destra pesante nel QQ-plot, confermata dall’istogramma e dagli indici di forma (skewness = 0.70, curtosi = 7.15, ben superiore al valore 3 di una distribuzione normale). - È presente una lieve eteroschedasticità (varianza dei residui leggermente crescente per i valori predetti più alti).

Queste violazioni delle assunzioni di normalità e omoschedasticità sono moderate e localizzate nelle code, dovute ai casi clinici estremi (i neonati prematuri con peso molto basso). Grazie all’elevata numerosità campionaria (n = 2497), il Teorema del Limite Centrale garantisce comunque l’affidabilità delle stime dei coefficienti e dei relativi test.

Valori influenti: l’analisi della distanza di Cook ha rivelato un’osservazione nettamente anomala, l’ID 1551, con un valore (0.83) significativamente diverso da tutte le altre. Esaminando i suoi dati emerge un’incoerenza fisica: a fronte di una gestazione a termine (38 settimane) e di un peso elevato (4370 g), la lunghezza registrata è di soli 315 mm (31.5 cm), valore incompatibile con un neonato di quel peso (atteso ~520 mm).

Si tratta quasi certamente di un errore di data entry sfuggito alla pulizia preliminare, che aveva controllato età materna e numero di gravidanze ma non la coerenza interna tra peso e dimensioni. È importante notare la differenza rispetto agli altri casi influenti (ID 310, 1780, 928), che sono invece prematuri reali (gestazione breve, peso basso, valori coerenti tra loro) con distanze di Cook molto inferiori: questi rappresentano casi clinici autentici e vanno mantenuti.

Alla luce di questa scoperta, nella sezione seguente procedo alla rimozione dell’osservazione 1551 e alla stima del modello sul dataset corretto, dopo aver confermato che sia effettivamente anomala rispetto alle altre di neonati con peso e gestazione simili:

# L'osservazione anomala
neonati %>%
  filter(ID == 1551) %>%
  select(ID, Gestazione, Peso, Lunghezza, Cranio, Sesso) %>%
  kable(caption = "Osservazione ID 1551") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Osservazione ID 1551
ID Gestazione Peso Lunghezza Cranio Sesso
1551 38 4370 315 374 F
# Confronto con neonati di peso elevato e gestazione a termine
neonati %>%
  filter(Peso > 4200, Gestazione >= 37) %>%
  arrange(desc(Peso)) %>%
  select(ID, Gestazione, Peso, Lunghezza, Cranio, Sesso) %>%
  kable(caption = "Neonati con peso > 4200g e gestazione a termine") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(height = "300px")
Neonati con peso > 4200g e gestazione a termine
ID Gestazione Peso Lunghezza Cranio Sesso
1920 39 4930 550 350 F
1306 41 4900 510 352 F
1433 41 4810 530 364 M
1639 40 4760 550 365 F
2076 40 4720 540 360 F
2392 40 4720 540 355 M
1963 42 4700 540 362 F
2235 41 4690 540 373 M
126 41 4680 545 370 M
2023 39 4650 510 354 M
1513 40 4620 560 367 M
368 41 4600 540 370 M
1293 38 4600 485 380 M
1838 40 4580 515 360 M
329 40 4560 540 340 M
2129 42 4550 540 365 M
1541 38 4540 530 343 M
1440 40 4480 540 375 M
1775 40 4480 530 380 M
420 40 4470 530 370 F
273 40 4440 540 370 F
791 41 4440 510 335 M
140 41 4420 530 362 F
1113 40 4420 520 380 F
303 41 4410 545 360 M
397 40 4410 540 370 M
428 40 4400 550 360 M
556 42 4400 530 370 M
2391 41 4400 565 366 F
2403 41 4400 535 357 F
1551 38 4370 315 374 F
1962 38 4370 530 340 F
165 40 4350 550 360 M
277 41 4350 530 372 M
1060 41 4350 540 360 M
1321 40 4340 515 383 M
59 40 4330 540 355 M
1036 40 4330 500 355 F
1085 39 4330 535 360 F
1222 40 4330 550 372 M
274 39 4320 530 350 M
513 41 4320 545 357 F
996 41 4320 535 367 M
478 42 4310 505 365 M
1404 41 4310 540 370 F
1745 40 4310 525 378 M
2046 40 4300 530 360 M
65 41 4290 530 367 M
1459 41 4290 525 360 M
2322 41 4290 525 360 M
1942 41 4280 545 365 M
2323 41 4280 530 370 M
375 38 4270 510 353 M
1826 41 4270 550 360 M
129 39 4260 540 345 M
1267 39 4260 545 343 F
1390 39 4260 520 367 F
1573 40 4260 540 366 F
565 40 4250 520 386 F
1283 40 4250 550 376 F
1885 40 4250 530 355 M
2000 41 4250 525 366 M
2343 39 4250 520 350 M
130 39 4240 485 352 M
184 41 4240 520 369 F
666 40 4240 555 345 F
958 40 4240 550 354 F
1491 42 4230 540 355 M
1370 41 4220 545 341 F
1533 40 4220 540 354 M
1583 40 4220 510 375 M
2442 41 4220 545 374 M

Filtrando tutti i neonati con peso superiore ai 4200 grammi e gestazione quasi a termine le lunghezze trovate oscillano tra i 485 e i 550 mm, mentre l’osservazione 1551 riporta 315 mm, un valore clinicamente non plausibile per un peso di 4370 grammi. Lo considero quindi un errore di data entry e lo rimuovo :

neonati_clean <- neonati %>% filter(ID != 1551)
nrow(neonati_clean)
## [1] 2496

Il dataset corretto contiene ora 2496 osservazioni.

Nuova stima del modello finale

Stimo il modello finale sul dataset corretto:

modello_finale_clean <- lm(Peso ~ N.gravidanze + Gestazione + Lunghezza + 
                            Cranio + Sesso, 
                          data = neonati_clean)
summary(modello_finale_clean)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + 
##     Sesso, data = neonati_clean)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1165.67  -179.88   -12.43   163.07  1410.65 
## 
## Coefficients:
##                Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)  -6683.6269   133.2063 -50.175 < 0.0000000000000002 ***
## N.gravidanze    13.1390     4.2590   3.085              0.00206 ** 
## Gestazione      29.6347     3.7376   7.929  0.00000000000000331 ***
## Lunghezza       10.8896     0.3019  36.067 < 0.0000000000000002 ***
## Cranio           9.9190     0.4228  23.459 < 0.0000000000000002 ***
## SessoM          78.1219    10.9964   7.104  0.00000000000157198 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 269.4 on 2490 degrees of freedom
## Multiple R-squared:  0.7371, Adjusted R-squared:  0.7366 
## F-statistic:  1396 on 5 and 2490 DF,  p-value: < 0.00000000000000022

Confronto tra modello prima e dopo la correzione

data.frame(
  Modello = c("Con osservazione 1551", "Senza osservazione 1551"),
  R2_adj = c(round(summary(modello_finale)$adj.r.squared, 4),
             round(summary(modello_finale_clean)$adj.r.squared, 4)),
  RMSE = c(round(sqrt(mean(residuals(modello_finale)^2)), 2),
           round(sqrt(mean(residuals(modello_finale_clean)^2)), 2)),
  Residuo_max = c(round(max(abs(residuals(modello_finale))), 2),
                  round(max(abs(residuals(modello_finale_clean))), 2))
) %>%
  kable(caption = "Confronto del modello prima e dopo la rimozione dell'osservazione anomala") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Confronto del modello prima e dopo la rimozione dell’osservazione anomala
Modello R2_adj RMSE Residuo_max
Con osservazione 1551 0.7264 274.42 2639.03
Senza osservazione 1551 0.7366 269.08 1410.65

Dal primo confronto la rimozione di una sola osservazione: -migliora R² di un punto percentuale -dimezza il residuo massimo che ora vale 1411 g -riduce di 5 g il RMSE (riduzione modesta trattandosi di una media su tutte le osservazioni)

Diagnostica del modello corretto

Verifico ora che la rimozione abbia migliorato la diagnostica dei residui.

par(mfrow = c(2, 2))
plot(modello_finale_clean)

par(mfrow = c(1, 1))
residui_clean <- residuals(modello_finale_clean)

data.frame(
  Statistica = c("Skewness", "Curtosi"),
  Prima = c(round(skewness(residuals(modello_finale)), 4),
            round(kurtosis(residuals(modello_finale)), 4)),
  Dopo = c(round(skewness(residui_clean), 4),
           round(kurtosis(residui_clean), 4))
) %>%
  kable(caption = "Forma dei residui prima e dopo la correzione") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Forma dei residui prima e dopo la correzione
Statistica Prima Dopo
Skewness 0.6967 0.3821
Curtosi 7.1544 4.0759

La rimozione dell’osservazione anomala ha migliorato sensibilmente la forma dei residui:

  • La skewness si è quasi dimezzata (da 0.70 a 0.38), indicando residui ora approssimativamente simmetrici.
  • La curtosi è scesa da 7.15 a 4.08, avvicinandosi nettamente al valore 3 della distribuzione normale: le code pesanti osservate in precedenza erano in larga parte imputabili a quella singola osservazione errata.

I nuovi grafici diagnostici confermano il miglioramento: il QQ-plot mostra residui che seguono la diagonale per quasi tutta l’estensione, con deviazioni minime alle estremità; il grafico Residuals vs Leverage non presenta più punti con distanza di Cook elevata.

Le lievi deviazioni residue dalla normalità (code ancora leggermente più pesanti del caso teorico) sono ora attribuibili ai casi clinici estremi autentici — i neonati prematuri con peso molto basso — che restano correttamente nel dataset in quanto rappresentativi del fenomeno reale. Considerando l’elevata numerosità campionaria, il modello può ritenersi adeguato e robusto per gli scopi predittivi e interpretativi del progetto.

Previsioni

Ora che il modello è pronto, come richiede il progetto, passo alla sua validazione testandolo su un caso specifico dato in input.

Caso richiesto:

neonata, terza gravidanza, 39 settimane

Il progetto richiede di stimare il peso di una neonata (Sesso = F), con madre alla terza gravidanza (N.gravidanze = 3) e parto alla 39ª settimana di gestazione.

I valori di lunghezza e cranio, non forniti, verranno sostituiti con le medie campionarie delle neonate femmine.

# valori medi di Lunghezza e Cranio per le femmine
medie_F <- neonati_clean %>%
  filter(Sesso == "F") %>%
  summarise(
    Lunghezza_media = mean(Lunghezza),
    Cranio_medio = mean(Cranio)
  )
medie_F
## # A tibble: 1 × 2
##   Lunghezza_media Cranio_medio
##             <dbl>        <dbl>
## 1            490.         338.
# Caso da predire
nuovo_caso <- data.frame(
  N.gravidanze = 3,
  Gestazione = 39,
  Lunghezza = medie_F$Lunghezza_media,
  Cranio = medie_F$Cranio_medio,
  Sesso = factor("F", levels = levels(neonati_clean$Sesso))
)

Previsione puntuale + intervallo di predizione

previsione <- predict(modello_finale_clean, newdata = nuovo_caso, 
                      interval = "prediction", level = 0.95)
previsione
##        fit      lwr      upr
## 1 3195.268 2666.493 3724.043

Il modello stima per questa neonata un peso di circa 3195 grammi.

Confronto tra scenari

Per rendere l’analisi più completa confronto diverse predizioni ottenute variando sesso e settimane di gestazione.

scenari <- data.frame(
  Descrizione = c("Femmina, 39 sett", "Maschio, 39 sett",
                  "Femmina, 32 sett (pretermine)", "Femmina, 41 sett (post-termine)"),
  N.gravidanze = c(3, 3, 3, 3),
  Gestazione = c(39, 39, 32, 41),
  Lunghezza = c(medie_F$Lunghezza_media, 
                mean(neonati_clean$Lunghezza[neonati_clean$Sesso == "M"]),
                medie_F$Lunghezza_media, medie_F$Lunghezza_media),
  Cranio = c(medie_F$Cranio_medio,
             mean(neonati_clean$Cranio[neonati_clean$Sesso == "M"]),
             medie_F$Cranio_medio, medie_F$Cranio_medio),
  Sesso = factor(c("F", "M", "F", "F"), levels = levels(neonati_clean$Sesso))
)

# Previsioni per tutti gli scenari
pred_scenari <- predict(modello_finale_clean, newdata = scenari, 
                        interval = "prediction", level = 0.95)

# Tabella riassuntiva
scenari %>%
  mutate(
    Peso_previsto = round(pred_scenari[, "fit"], 0),
    IC_inf = round(pred_scenari[, "lwr"], 0),
    IC_sup = round(pred_scenari[, "upr"], 0)
  ) %>%
  select(Descrizione, Gestazione, Sesso, Peso_previsto, IC_inf, IC_sup) %>%
  kable(caption = "Peso previsto in diversi scenari (intervallo di predizione 95%)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Peso previsto in diversi scenari (intervallo di predizione 95%)
Descrizione Gestazione Sesso Peso_previsto IC_inf IC_sup
Femmina, 39 sett 39 F 3195 2666 3724
Maschio, 39 sett 39 M 3428 2899 3957
Femmina, 32 sett (pretermine) 32 F 2988 2457 3519
Femmina, 41 sett (post-termine) 41 F 3255 2725 3784

Commento sulle previsioni

Per la neonata richiesta dal progetto (femmina, terza gravidanza, 39 settimane, dimensioni medie), il modello stima un peso di 3195 grammi, con intervallo di predizione al 95% pari a [2666 ; 3724]. Il valore puntuale è clinicamente plausibile e coerente con il peso atteso per una neonata a termine.

L’ampiezza dell’intervallo di predizione (±530 g circa) merita attenzione: riflette la variabilità individuale intrinseca dei neonati. Il modello stima con buona precisione il peso medio di neonati con date caratteristiche, ma il peso del singolo individuo resta soggetto a una variabilità considerevole, dovuta a fattori non inclusi nel modello (genetici, nutrizionali, ambientali). Questo non è un limite del modello ma una caratteristica intrinseca del fenomeno.

Il confronto tra scenari illustra il funzionamento del modello e a tale scopo sono state variate a turno le feature per valutarne il singolo effetto:

  • Effetto del sesso: un maschio con dimensioni medie maschili pesa circa 233 g in più di una femmina con dimensioni medie femminili.Questo scarto è superiore al coefficiente puro del sesso (+78 g): la differenza aggiuntiva deriva dall’aver attribuito ai due sessi le rispettive dimensioni medie (lunghezza e cranio), che nei maschi sono maggiori.
  • Effetto della gestazione: passando da 39 a 32 settimane il peso previsto cala di circa 207 g (coerente con il coefficiente di ~30 g per settimana). Va però precisato che questo scenario è un’astrazione: mantenere lunghezza e cranio ai valori medi a termine, serve in linea teorica a isolare l’effetto della durata gestazionale, ceteris paribus.

Allo stesso modo il terzo esempio aumenta la durata gestazionale(di 2 settimane) che porta a un aumento del peso predetto mantenendo comunque una coerenza clinica.

In sintesi, il modello fornisce previsioni clinicamente sensate e si presta bene a quantificare l’impatto delle singole variabili, mantenendo però la consapevolezza dei limiti predittivi sul singolo caso.

Visualizzazione dei risultati del modello

Nella fase finale presento le visualizzazioni più utili a cogliere le relazioni significative tra le variabili del modello.

Peso in funzione della Lunghezza, per sesso

La Lunghezza è il predittore con l’effetto più forte. Visualizzo quindi la sua relazione con il Peso, distinguendo tra i due sessi.

ggplot(neonati_clean, aes(x = Lunghezza, y = Peso, color = Sesso)) +
  geom_point(alpha = 0.3, size = 1) +
  geom_smooth(method = "lm", se = TRUE) +
  labs(title = "Peso in funzione della Lunghezza, per sesso",
       x = "Lunghezza (mm)",
       y = "Peso (g)",
       color = "Sesso") +
  theme_minimal()

Peso in funzione della Gestazione

La durata della gestazione è un’altra delle variabili di interesse del progetto. Visualizzo pertanto la relazione con il Peso.

ggplot(neonati_clean, aes(x = Gestazione, y = Peso)) +
  geom_point(alpha = 0.3, size = 1, color = "steelblue") +
  geom_smooth(method = "lm", color = "darkred", se = TRUE) +
  labs(title = "Peso in funzione della settimana di gestazione",
       x = "Settimane di gestazione",
       y = "Peso (g)") +
  theme_minimal()

Valori osservati vs valori predetti

Questo grafico mostra la capacità predittiva complessiva del modello: confronta i pesi reali con quelli stimati. Più i punti si allineano sulla diagonale, migliore è la previsione.

neonati_clean %>%
  mutate(Peso_predetto = predict(modello_finale_clean)) %>%
  ggplot(aes(x = Peso_predetto, y = Peso)) +
  geom_point(alpha = 0.3, size = 1, color = "steelblue") +
  geom_abline(intercept = 0, slope = 1, color = "darkred", linewidth = 1) +
  labs(title = "Valori osservati vs valori predetti",
       subtitle = "La linea rossa rappresenta la previsione perfetta (osservato = predetto)",
       x = "Peso predetto (g)",
       y = "Peso osservato (g)") +
  theme_minimal()

Commento sulle visualizzazioni

I tre grafici illustrano in modo complementare il funzionamento del modello:

Peso vs Lunghezza per sesso: emerge la relazione lineare positiva più forte del modello. Le rette di regressione per maschi e femmine sono quasi parallele e molto vicine tra loro, a conferma che — a parità di lunghezza — il sesso incide solo marginalmente (coerente con il coefficiente di +78 g), mentre la lunghezza rappresenta il principale driver del peso. La nuvola di punti compatta attorno alle rette indica una buona capacità esplicativa.

Peso vs Gestazione: la relazione è positiva ma visibilmente più dispersa rispetto alla lunghezza, segno che la gestazione, pur significativa, spiega una quota minore della variabilità del peso. Si nota la forte concentrazione dei parti tra la 38ª e la 41ª settimana e la coda dei nati prima del termine effettivo.

Valori osservati vs predetti: i punti si distribuiscono attorno alla diagonale di previsione perfetta in modo compatto e simmetrico, senza pattern sistematici. Questo conferma visivamente la buona capacità predittiva del modello (R² = 0.74) e l’assenza di distorsioni evidenti lungo l’intero intervallo di pesi.

Nota: le rette tracciate nei primi due grafici rappresentano regressioni semplici sulla singola variabile, utili a visualizzare la direzione e la forza delle relazioni; non corrispondono esattamente ai coefficienti del modello multiplo, che misurano l’effetto di ciascuna variabile al netto delle altre.

Conclusioni

L’analisi condotta sul campione di 2496 neonati (dopo la rimozione delle osservazioni errate) ha permesso di definire i fattori associati al peso neonatale e di costruire un modello predittivo affidabile.

Sintesi dei risultati

Verifica delle ipotesi inferenziali:

  • Tipo di parto e ospedale (Ipotesi 1): il test del chi quadrato non ha rilevato differenze significative nella proporzione di parti cesarei tra i tre ospedali (p = 0.575). Le strutture seguono prassi sostanzialmente omogenee.
  • Confronto con la popolazione (Ipotesi 2): il peso medio del campione è risultato compatibile con il valore di riferimento nazionale (3300 g), mentre la lunghezza media ha mostrato una differenza statisticamente significativa ma clinicamente trascurabile (5 mm, attribuibile a fattori metodologici). Il campione può considerarsi rappresentativo della popolazione italiana.
  • Differenze tra sessi (Ipotesi 3): tutte le misure antropometriche (peso, lunghezza, cranio) differiscono significativamente tra maschi e femmine, con i maschi sistematicamente più grandi. La differenza di peso (+247 g) ha un’effettiva rilevanza clinica.

Modello predittivo:

Il modello di regressione lineare multipla finale spiega il 73.7% della variabilità del peso (R² aggiustato) attraverso cinque predittori: numero di gravidanze, settimane di gestazione, lunghezza, diametro cranico e sesso. I predittori antropometrici (lunghezza e cranio) e la gestazione risultano i fattori più influenti. L’errore tipico di previsione è di circa 269 grammi.

Due risultati meritano particolare attenzione:

  • Il fumo materno, pur essendo una variabile di interesse del progetto, non è risultato un predittore significativo del peso nel modello. Le cause più probabili sono la bassa numerosità delle fumatrici nel campione (4%) e il possibile effetto di mediazione attraverso le variabili di dimensione fetale. Questo non contraddice la letteratura clinica sui rischi del fumo, ma riflette i limiti di questo specifico campione.
  • L’ospedale di nascita non contribuisce alla previsione del peso, in coerenza con quanto rilevato nell’Ipotesi 1.

Qualità e robustezza del modello

La diagnostica dei residui ha confermato l’adeguatezza del modello, permettendo inoltre di individuare e correggere un errore di data entry (osservazione con peso e lunghezza incompatibili) sfuggito alla pulizia del dataset preliminare. La rimozione di tale osservazione ha migliorato sia la capacità predittiva sia la normalità dei residui, senza alterare la struttura del modello.

Raccomandazioni operative per Neonatal Health Solutions

  1. Utilizzare il modello come strumento di screening: il modello consente di stimare il peso atteso del neonato a partire dalle misure ecografiche prenatali (lunghezza, diametro cranico) e dai dati gestazionali. Può quindi aiutare nell’identificazione precoce di neonati a rischio di basso peso, utile per la pianificazione dell’assistenza.

  2. Concentrare le misurazioni sui predittori più informativi: lunghezza, diametro cranico e settimane di gestazione sono le variabili che meglio predicono il peso. L’attenzione andrà quindi convogliata nella raccolta di questi dati anche a discapito di quelli meno predittivi.

  3. Migliorare i controlli di qualità sui dati: l’individuazione di un errore di data entry (peso e lunghezza incompatibili) suggerisce il bisogno di introdurre controlli automatici di coerenza al momento dell’inserimento dei dati clinici, per esempio segnalando combinazioni fisicamente non plausibili.

  4. Approfondire l’effetto del fumo con campioni dedicati: data l’importanza clinica del fumo in gravidanza ma la sua bassa numerosità in questo campione, si raccomanda uno studio mirato con una rappresentanza adeguata di fumatrici, per quantificarne correttamente l’impatto.

  5. Interpretare le previsioni con consapevolezza dei limiti: il modello stima accuratamente il peso medio, ma il singolo neonato presenta una variabilità individuale ampia (intervallo di predizione ±530 g). Le stime vanno quindi trattate come tendenza e non come valori certi.

Limiti dell’analisi

  • Il modello include variabili (lunghezza, cranio) misurabili con precisione solo in prossimità o dopo la nascita; il loro utilizzo a scopo predittivo prenatale dipende dalla disponibilità di misure ecografiche affidabili.
  • La numerosità ridotta di alcune sottopopolazioni (in particolare le fumatrici) limita la capacità del modello di cogliere alcuni effetti.
  • Il modello è lineare e additivo: non cattura eventuali relazioni complesse, sebbene l’esplorazione di termini non lineari e interazioni non abbia evidenziato miglioramenti sostanziali.
  • I valori di riferimento della popolazione utilizzati nell’Ipotesi 2 sono approssimativi e ricavati da fonti pubbliche; un confronto più rigoroso richiederebbe dati normativi specifici per popolazione e metodo di misurazione.
  • Il dataset non include altre variabili potenzialmente rilevanti (peso e altezza dei genitori, alimentazione, condizioni socioeconomiche) che spiegherebbero parte della variabilità residua.

In conclusione, il progetto ha prodotto un modello solido e interpretabile per la previsione del peso neonatale, con applicazioni concrete per il supporto alle decisioni cliniche, pur nei limiti propri di un’analisi che verte su un singolo campione.