MIN_ANNI_MADRE = 11
#' Crea una variabile categoriale a partire da una variabile numerica.
#'
#' Verifica che il numero di etichette corrisponda al numero di intervalli
#' definiti nei break e crea una nuova colonna categoriale utilizzando
#' la funzione `cut()`.
#'
#' @param dati Data frame contenente i dati.
#' @param variabile Nome della variabile numerica da categorizzare.
#' @param breaks Vettore dei punti di separazione degli intervalli.
#' @param labels Vettore delle etichette associate agli intervalli.
#' @param nome_categoria Nome della nuova variabile categoriale.
#'
#' @return Il data frame con la nuova variabile categoriale.
crea_categoria <- function(dati, variabile, breaks, labels, nome_categoria){
  if(length(labels) != length(breaks) - 1){
    stop(
      paste(
        "Errore in", nome_categoria, ":",
        length(breaks) - 1,
        "etichette richieste ma ne hai fornite",
        length(labels)
      )
    )
  }
  dati[[nome_categoria]] <- cut(
    dati[[variabile]],
    breaks = breaks,
    labels = labels
  )
  dati
}

#' Calcola la tabella delle frequenze di una variabile.
#'
#' Restituisce il numero di osservazioni e la percentuale associata
#' a ciascuna modalità della variabile selezionata.
#'
#' @param dati Data frame contenente i dati.
#' @param variabile Nome della variabile di cui calcolare la distribuzione.
#'
#' @return Un data frame contenente:
#' \itemize{
#'   \item la modalità della variabile;
#'   \item il numero di osservazioni (`n`);
#'   \item la percentuale sul totale.
#' }
tabella_frequenze <- function(dati, variabile) {

  dati %>%
    count(.data[[variabile]]) %>%
    mutate(
      Percentuale = paste0(round(n / sum(n) * 100, 2), "%")
    )
}

#' Controlla la validità dei valori di una variabile categoriale.
#'
#' Visualizza i valori osservati, il numero di valori mancanti
#' ed eventuali modalità non appartenenti all'insieme dei valori attesi.
#'
#' @param dati Data frame contenente i dati.
#' @param variabile Nome della variabile da controllare.
#' @param valori_attesi Vettore contenente i valori ammessi.
#'
#' @return Nessun valore restituito. La funzione stampa a video
#' informazioni di controllo sulla variabile.

controlla_categorie <- function(dati, variabile, valori_attesi) {

  valori_osservati <- sort(unique(dati[[variabile]]))
  valori_non_validi <- setdiff(valori_osservati, valori_attesi)

  data.frame(
    Variabile = variabile,
    `Valori osservati` = paste(valori_osservati, collapse = ", "),
    `Valori mancanti` = sum(is.na(dati[[variabile]])),
    `Valori non validi` = if (length(valori_non_validi) == 0)
      "Nessuno"
    else
      paste(valori_non_validi, collapse = ", "),
    check.names = FALSE
  )
}


#' Stampa una tabella formattata con kable e kableExtra.
#'
#' La funzione formatta un data frame o una matrice come tabella HTML,
#' applicando uno stile uniforme tramite il pacchetto kableExtra.
#' Se l'oggetto fornito non è un data frame né una matrice,
#' viene convertito automaticamente in una tabella.
#'
#' @param x Oggetto da visualizzare come tabella.
#' @param caption Titolo della tabella.
#' @param align Allineamento delle colonne.
#' @param full_width Valore logico che indica se la tabella deve occupare
#' l'intera larghezza disponibile.
#'
#' @return Una tabella formattata pronta per la visualizzazione nel report.
stampa_tabella <- function(x,
                           caption = NULL,
                           align = "c",
                           full_width = FALSE) {

  if (!is.data.frame(x) && !is.matrix(x)) {
    x <- as.data.frame(t(x))
  }

  kable(
    x,
    caption = caption,
    align = align
  ) |>
    kable_styling(
      bootstrap_options = c("striped", "hover", "condensed"),
      full_width = full_width
    )
}


#' Calcola e stampa le statistiche descrittive delle variabili numeriche.
#'
#' La funzione seleziona automaticamente le variabili numeriche presenti
#' in un data frame e ne calcola le principali statistiche descrittive:
#' minimo, primo quartile, mediana, media, terzo quartile e massimo.
#' I risultati vengono visualizzati in una tabella formattata.
#'
#' @param df Data frame contenente le variabili da analizzare.
#'
#' @return Una tabella con le statistiche descrittive delle variabili numeriche.
statistiche_descrittive <- function(df) {

  num <- df[sapply(df, is.numeric)]

  tabella <- do.call(
    rbind,
    lapply(num, function(x) {
      c(
        Min = min(x, na.rm = TRUE),
        `1° Qu.` = quantile(x, 0.25, na.rm = TRUE),
        Mediana = median(x, na.rm = TRUE),
        Media = mean(x, na.rm = TRUE),
        `3° Qu.` = quantile(x, 0.75, na.rm = TRUE),
        Max = max(x, na.rm = TRUE)
      )
    })
  )

  tabella <- data.frame(
    Variabile = rownames(tabella),
    round(tabella, 2),
    row.names = NULL
  )

  stampa_tabella(
    tabella,
    caption = "Statistiche descrittive delle variabili numeriche"
  )
}

#' Stampa una singola statistica in formato tabellare.
#'
#' La funzione crea una tabella composta dal nome della statistica
#' e dal relativo valore, utilizzando la funzione `stampa_tabella()`
#' per mantenere uno stile uniforme nel report.
#'
#' @param nome Nome della statistica.
#' @param valore Valore della statistica.
#' @param caption Titolo della tabella.
#'
#' @return Una tabella contenente il nome e il valore della statistica.
stampa_statistica <- function(nome, valore, caption = NULL) {
  stampa_tabella(
    data.frame(
      Statistica = nome,
      Valore = valore
    ),
    caption = caption
  )
}

#' Esegue un one sample t-test e stampa i risultati in tabella.
#'
#' La funzione verifica se la media campionaria di una variabile numerica
#' differisce significativamente da un valore ipotizzato della popolazione.
#'
#' @param dati Vettore numerico contenente i dati.
#' @param nome Nome della variabile analizzata.
#' @param mu Valore della media ipotizzata sotto H0.
#'
#' @return Una tabella con statistiche del test, intervallo di confidenza
#' e stima della media campionaria.
test_media <- function(dati, nome, mu) {
  
  test <- t.test(
    dati,
    mu = mu
  )
  
  risultato <- data.frame(
    Variabile = nome,
    `Media campionaria` = round(mean(dati, na.rm = TRUE), 2),
    `Media ipotizzata` = mu,
    `Statistica t` = round(unname(test$statistic), 2),
    `Gradi liberta` = unname(test$parameter),
    `p-value` = format.pval(test$p.value, digits = 2),
    `IC 95% inferiore` = round(test$conf.int[1], 2),
    `IC 95% superiore` = round(test$conf.int[2], 2),
    check.names = FALSE
  )
  
  stampa_tabella(
    risultato,
    caption = paste(
      "One Sample t-test per",
      nome
    )
  )
}

#' Esegue un two sample t-test tra due gruppi e stampa i risultati.
#'
#' Confronta la media di una variabile numerica tra due livelli
#' di una variabile categoriale.
#'
#' @param formula Formula del tipo variabile_numerica ~ gruppo.
#' @param dati Data frame contenente le variabili.
#' @param nome Nome descrittivo della variabile analizzata.
#'
#' @return Una tabella con le statistiche del test.
test_confronto_gruppi <- function(formula, dati, nome) {
  
  test <- t.test(
    formula,
    data = dati
  )
  
  variabile <- all.vars(formula)[1]
  gruppo <- all.vars(formula)[2]
  
  medie <- aggregate(
    dati[[variabile]],
    list(dati[[gruppo]]),
    mean,
    na.rm = TRUE
  )
  
  risultato <- data.frame(
    Variabile = nome,
    Gruppi = paste(levels(dati[[gruppo]]), collapse = " vs "),
    `Media gruppo 1` = round(medie$x[1], 2),
    `Media gruppo 2` = round(medie$x[2], 2),
    `Differenza medie` = round(diff(medie$x), 2),
    `Statistica t` = round(unname(test$statistic), 2),
    `Gradi liberta` = round(unname(test$parameter), 2),
    `p-value` = format.pval(test$p.value, digits = 2),
    `IC 95% inferiore` = round(test$conf.int[1], 2),
    `IC 95% superiore` = round(test$conf.int[2], 2),
    check.names = FALSE
  )
  
  stampa_tabella(
    risultato,
    caption = paste(
      "Two Sample t-test per",
      nome
    )
  )
}

#' Esegue una ANOVA a una via e stampa i risultati.
#'
#' Confronta la media di una variabile numerica tra più gruppi
#' definiti da una variabile categoriale.
#'
#' @param formula Formula del modello del tipo variabile ~ gruppo.
#' @param dati Data frame contenente le variabili.
#' @param nome Nome descrittivo dell'analisi.
#'
#' @return Una tabella contenente la statistica F e il p-value.

test_anova <- function(formula, dati, nome) {
  
  modello <- aov(
    formula,
    data = dati
  )
  
  risultato <- summary(modello)[[1]]
  
  tabella <- data.frame(
    Fonte = rownames(risultato),
    `Gradi liberta` = risultato$Df,
    `Somma quadrati` = round(risultato$`Sum Sq`, 2),
    `Media quadratica` = round(risultato$`Mean Sq`, 2),
    `Statistica F` = round(risultato$`F value`, 2),
    `p-value` = format.pval(
      risultato$`Pr(>F)`,
      digits = 4
    ),
    check.names = FALSE
  )
  
  rownames(tabella) <- NULL
  
  stampa_tabella(
    tabella,
    caption = paste(
      "ANOVA a una via per",
      nome
    )
  )
}

#' Esegue un test di correlazione di Pearson e stampa i risultati.
#'
#' Valuta la presenza di una correlazione lineare significativa
#' tra due variabili quantitative.
#'
#' @param x Prima variabile numerica.
#' @param y Seconda variabile numerica.
#' @param nome_x Nome della prima variabile.
#' @param nome_y Nome della seconda variabile.
#'
#' @return Una tabella con coefficiente di correlazione,
#' statistica del test e p-value.

test_correlazione <- function(x, y, nome_x, nome_y) {
  
  test <- cor.test(
    x,
    y,
    method = "pearson"
  )
  
  risultato <- data.frame(
    Variabile_1 = nome_x,
    Variabile_2 = nome_y,
    `Coefficiente Pearson (r)` = round(unname(test$estimate), 2),
    `Statistica t` = round(unname(test$statistic), 2),
    `Gradi liberta` = unname(test$parameter),
    `p-value` = format.pval(test$p.value, digits = 2),
    `IC 95% inferiore` = round(test$conf.int[1], 2),
    `IC 95% superiore` = round(test$conf.int[2], 2),
    check.names = FALSE
  )
  
  stampa_tabella(
    risultato,
    caption = paste(
      "Correlazione di Pearson tra",
      nome_x,
      "e",
      nome_y
    )
  )
}

EDA

Dataset

Eseguo un’analisi preliminare del dataset per verificare la presenza di dati mancanti o valori anomali, così da poterli gestire prima dell’addestramento del modello ed evitare che influenzino le previsioni.

I valori mancanti o palesemente errati sono stati sostituiti con la mediana, poiché il loro numero è ridotto e questa misura è robusta rispetto ai valori estremi.

stampa_tabella(
  head(dati_neonati),
  caption = "Prime sei osservazioni del dataset"
)
Prime sei osservazioni del dataset
Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto Ospedale Sesso
26 0 0 42 3380 490 325 Nat osp3 M
21 2 0 39 3150 490 345 Nat osp1 F
34 3 0 38 3640 500 375 Nat osp2 M
28 1 0 41 3690 515 365 Nat osp2 M
20 0 0 38 3700 480 335 Nat osp3 F
32 0 0 40 3200 495 340 Nat osp2 F
statistiche_descrittive(dati_neonati)
Statistiche descrittive delle variabili numeriche
Variabile Min X1..Qu..25. Mediana Media X3..Qu..75. Max
Anni.madre 0 25 28 28.16 32 46
N.gravidanze 0 0 1 0.98 1 12
Fumatrici 0 0 0 0.04 0 1
Gestazione 25 38 39 38.98 40 43
Peso 830 2990 3300 3284.08 3620 4930
Lunghezza 310 480 500 494.69 510 565
Cranio 235 330 340 340.03 350 390
stampa_tabella(
  names(dati_neonati),
  caption = "Nomi colonne dataset"
)
Nomi colonne dataset
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto Ospedale Sesso
stampa_tabella(
  colSums(is.na(dati_neonati)),
  caption = "Somma valori nulli per colonna"
)
Somma valori nulli per colonna
Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto Ospedale Sesso
0 0 0 0 0 0 0 0 0 0

Anni Madre

tabella_eta <- as.data.frame.matrix(
  t(table(
    dati_neonati$Anni.madre[
      dati_neonati$Anni.madre <= MIN_ANNI_MADRE - 1
    ],
    useNA = "ifany"
  ))
)

stampa_tabella(
  tabella_eta,
  caption = "Frequenza delle età materne inferiori a 11 anni"
)
Frequenza delle età materne inferiori a 11 anni
0 1
1 1
mediana_anni_madre <- median(
  dati_neonati$Anni.madre[
    dati_neonati$Anni.madre >= MIN_ANNI_MADRE
  ],
  na.rm = TRUE
)

dati_neonati$Anni.madre[
  is.na(dati_neonati$Anni.madre) |
  (dati_neonati$Anni.madre >= 0 &
     dati_neonati$Anni.madre <= MIN_ANNI_MADRE - 1)
] <- mediana_anni_madre

stampa_tabella(
  summary(dati_neonati$Anni.madre),
  caption = "Statistiche descrittive per gli Anni.madre"
)
Statistiche descrittive per gli Anni.madre
Var1 Var2 Freq
A Min. 13.000
A 1st Qu. 25.000
A Median 28.000
A Mean 28.186
A 3rd Qu. 32.000
A Max. 46.000
dati_neonati <- crea_categoria(
  dati_neonati,
  "Anni.madre",
  c(-Inf, 19, 24, 29, 34, Inf),
  c(
    "Adolescente",
    "Giovane adulta (20-24)",
    "Giovane adulta (25-29)",
    "Giovane adulta (30-34)",
    "Età materna avanzata"
  ),
  "Categorie_Anni_Madre"
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Categorie_Anni_Madre"),
  "Frequenze assolute e relative delle categorie anni madre"
)
Frequenze assolute e relative delle categorie anni madre
Categorie_Anni_Madre n Percentuale
Adolescente 109 4.36%
Giovane adulta (20-24) 486 19.44%
Giovane adulta (25-29) 909 36.36%
Giovane adulta (30-34) 712 28.48%
Età materna avanzata 284 11.36%
ggplot(dati_neonati, aes(x = Anni.madre)) +
  geom_histogram(binwidth = 2,
                 fill = "steelblue",
                 color = "black") +
  labs(
    title = "Distribuzione dell'età della madre",
    x = "Età della madre (anni)",
    y = "Frequenza"
  ) +
  theme_minimal()

# Relazione anni.madre-peso
levels(dati_neonati$Categorie_Anni_Madre) <- c(
  "1 - Adolescente (<20 anni)",
  "2 - Giovane adulta (20-24 anni)",
  "3 - Giovane adulta (25-29 anni)",
  "4 - Giovane adulta (30-34 anni)",
  "5 - Età materna avanzata (>=35 anni)"
)

dati_neonati$Codice_anni_madre <- as.numeric(
  dati_neonati$Categorie_Anni_Madre
)

ggplot(
  dati_neonati,
  aes(
    x = Codice_anni_madre,
    y = Peso,
    fill = Categorie_Anni_Madre
  )
) +
  geom_boxplot() +
  scale_x_continuous(
    breaks = 1:5,
    labels = 1:5
  ) +
  labs(
    title = "Distribuzione del peso per categoria di età materna",
    x = "Categoria età madre (codice)",
    y = "Peso alla nascita (grammi)",
    fill = "Categoria età madre"
  ) +
  theme_minimal()

Analisi Anni.madre

Anni.madre:

  • individuati valori non realistici (da 0 a 10 anni);
  • tali valori sono stati considerati errati e sostituiti con la mediana calcolata sulle età valide (> 10 anni);
  • gli eventuali valori NA sono stati sostituiti con la stessa mediana.
  • Ho suddiviso i valori in classi come Adolescente (< 20 anni), Giovane adulta(20-24), Giovane adulta(25-29),Giovane adulta(30-34), Età materna avanzata (>= 35 anni)
  • La fascia di età in cui si fanno più figli è quella di 25-29 anni
  • Dal grafico a barre sembra che la variabile anni.madre segua una normale. Si proverà in seguito un test per la normalità
  • Il peso mediano sembra mostrare una lieve crescita all’aumentare dell’età materna. La categoria delle madri in età avanzata(>=35) presenta tuttavia una distribuzione più ampia e alcuni valori anomali inferiori, indicando una maggiore variabilità del peso all’interno del gruppo

N.gravidanze

dati_neonati <- crea_categoria(
  dati_neonati,
  "N.gravidanze",
  c(-Inf, 0, 1, 2, Inf),
  c(
    "0 gravidanze precedenti",
    "1 gravidanza precedente",
    "2 gravidanze precedenti",
    "3 gravidanze o più"
  ),
  "Categorie_gravidanze"
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Categorie_gravidanze"),
  "Frequenze assolute e relative delle categorie gravidanze"
)
Frequenze assolute e relative delle categorie gravidanze
Categorie_gravidanze n Percentuale
0 gravidanze precedenti 1096 43.84%
1 gravidanza precedente 818 32.72%
2 gravidanze precedenti 340 13.6%
3 gravidanze o più 246 9.84%
ggplot(dati_neonati, aes(x = N.gravidanze)) +
  geom_bar(fill = "steelblue")

Analisi N.gravidanze

N.gravidanze:

  • Non sono stati riscontrati valori mancanti o non plausibili, pertanto non è stato necessario effettuare operazioni di imputazione o correzione.
  • Il 75% delle madri ha al massimo 1 gravidanza precedente
  • La distribuzione è asimmetrica a destra poiché presenta una coda più lunga verso i valori elevati.
  • Le madri con tre o più gravidanze sono state raggruppate in un’unica categoria, poiché le singole classi presentavano una numerosità ridotta.
dati_neonati <- crea_categoria(
  dati_neonati,
  "Peso",
  c(-Inf, 1000, 1500, 2500, 4500, Inf),
  c(
    "Estremamente Basso (<1000 g)",
    "Molto Basso (1000-1499 g)",
    "Basso (1500-2499 g)",
    "Normopeso (2500-4499 g)",
    "Macrosomia fetale (>=4500 g)"
  ),
  "Categoria_peso"
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Categoria_peso"),
  "Frequenze assolute e relative delle categorie peso"
)
Frequenze assolute e relative delle categorie peso
Categoria_peso n Percentuale
Estremamente Basso (<1000 g) 6 0.24%
Molto Basso (1000-1499 g) 18 0.72%
Basso (1500-2499 g) 123 4.92%
Normopeso (2500-4499 g) 2335 93.4%
Macrosomia fetale (>=4500 g) 18 0.72%
ggplot(dati_neonati, aes(x = Peso)) +
  geom_histogram(
    binwidth = 200,
    fill = "steelblue",
    color = "black"
  ) +
  labs(
    title = "Distribuzione del peso alla nascita",
    x = "Peso (grammi)",
    y = "Frequenza"
  ) +
  theme_minimal()

Analisi Peso

Peso:

  • La variabile Peso non presenta valori mancanti né valori non plausibili. Il peso minimo osservato è pari a 830 g, compatibile con neonati estremamente prematuri, mentre il peso massimo è di 4930 g, valore elevato ma clinicamente possibile. La distribuzione risulta concentrata tra 2990 g e 3620 g, con una mediana di 3300 g.
  • La distribuzione è lievemente asimmetrica a sinistra poiché presenta una coda più lunga verso i valori più bassi
  • Ho suddiviso in classi identificando delle categorie di peso utilizzando questo sito come fonte: https://www.medicoverhospitals.in/it/articles/handling-an-underweight-baby. Anche se alcune classi sono minoritarie, ho preferito usare delle categorie universalmente riconosciute in ambito medico cosi da ottenere un’analisi generalizzabile e riutilizzabile

Gestazione

dati_neonati <- crea_categoria(
  dati_neonati,
  "Gestazione",
  c(-Inf, 28, 32, 39, 41, 42, Inf),
  c(
    "Estremamente pretermine (<28 settimane)",
    "Molto pretermine (28-31 settimane)",
    "Pretermine moderato (32-38 settimane)",
    "Pieno termine (39-40 settimane)",
    "Termine tardivo (41 settimane)",
    "Post-termine (>=42 settimane)"
  ),
  "Categoria_gestazione"
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Categoria_gestazione"),
  "Frequenze assolute e relative delle categorie gestazione"
)
Frequenze assolute e relative delle categorie gestazione
Categoria_gestazione n Percentuale
Estremamente pretermine (<28 settimane) 8 0.32%
Molto pretermine (28-31 settimane) 25 1%
Pretermine moderato (32-38 settimane) 1339 53.56%
Pieno termine (39-40 settimane) 1070 42.8%
Termine tardivo (41 settimane) 56 2.24%
Post-termine (>=42 settimane) 2 0.08%
ggplot(dati_neonati, aes(x = Gestazione)) +
  geom_bar(
    fill = "darkgreen",
    color = "black"
  ) +
  labs(
    title = "Distribuzione delle settimane di gestazione",
    x = "Settimane di gestazione",
    y = "Frequenza"
  ) +
  theme_minimal()

#relazione gestazione-peso
ggplot(dati_neonati, aes(x = Gestazione, y = Peso)) +
  geom_point() +
  geom_smooth(method = "lm") +
  labs(
    title = "Relazione tra settimane di gestazione e peso alla nascita",
    x = "Settimane di gestazione",
    y = "Peso (grammi)"
  ) +
  theme_minimal()

#gestazione-peso distribuzione
levels(dati_neonati$Categoria_gestazione) <- c(
  "1 - Estremamente pretermine (<28 settimane)",
    "2 - Molto pretermine (28-31 settimane)",
    "3 - Pretermine moderato(32-38 settimane)",
    "4 - Pieno-termine(39-40 settimane)",
    "5 - Termine-tardivo(41 settimane)",
    "6 - Post-termine(>=42 settimane)"
)
dati_neonati$Codice_gestazione <- as.numeric(dati_neonati$Categoria_gestazione)

ggplot(
  dati_neonati,
  aes(
    x = Codice_gestazione,
    y = Peso,
    fill = Categoria_gestazione
  )
) +
  geom_boxplot() +
  scale_x_continuous(
    breaks = 1:6,
    labels = 1:6
  ) +
  labs(
    title = "Distribuzione del peso per categoria di gestazione",
    x = "Categoria gestazionale (codice)",
    y = "Peso (grammi)",
    fill = "Categoria"
  ) +
  theme_minimal()

Analisi Gestazione

  • Gestazione:

    • La variabile Gestazione assume valori compresi tra 25 e 43 settimane. Sebbene il valore minimo rappresenti un parto estremamente prematuro, esso rientra nell’intervallo clinicamente plausibile e pertanto non è stato considerato un’anomalia. La maggior parte delle osservazioni è concentrata tra 38 e 40 settimane, indicando una prevalenza di gravidanze portate a termine.
    • La distribuzione sembra essere assimetrica a sinistra, poichè ha una coda più lunga per valori bassi
    • Ho suddiviso in classi identificando delle categorie di durata gestazione utilizzando questo sito come fonte: https://www.nurse24.it/ostetrica/parto/pretermine-neonati-prematuri-conseguenze-sulla-salute.html. Anche se alcune classi sono minoritarie, ho preferito usare delle categorie universalmente riconosciute in ambito medico cosi da ottenere un’analisi generalizzabile e riutilizzabile
  • Gestazione - Peso:

    • gestazione e peso sembrano essere correlati. All’aumentare delle settimane di gestazione aumenta il peso. Questa ipotesi sarà considerata all’interno di opportuni test statistici

Lunghezza

p10_lunghezza <- quantile(dati_neonati$Lunghezza, 0.10, na.rm = TRUE)
p90_lunghezza <- quantile(dati_neonati$Lunghezza, 0.90, na.rm = TRUE)

lunghezza_breaks <- c(-Inf, p10_lunghezza, p90_lunghezza, Inf)

lunghezza_labels <- c(
  "Lunghezza bassa (≤ P10)",
  "Lunghezza nella norma (P10-P90)",
  "Lunghezza elevata (> P90)"
)

dati_neonati <- crea_categoria(
  dati_neonati,
  "Lunghezza",
  lunghezza_breaks,
  lunghezza_labels,
  "Categoria_lunghezza"
)

tabella_percentili <- data.frame(
  Statistica = c("P10 Lunghezza [mm]", "P90 Lunghezza [mm]"),
  Valore = c(p10_lunghezza, p90_lunghezza)
)

stampa_tabella(
  tabella_percentili,
  caption = "Percentili della lunghezza"
)
Percentili della lunghezza
Statistica Valore
10% P10 Lunghezza [mm] 465
90% P90 Lunghezza [mm] 520
stampa_tabella(
  tabella_frequenze(dati_neonati, "Categoria_lunghezza"),
  "Frequenze assolute e relative delle categorie lunghezza"
)
Frequenze assolute e relative delle categorie lunghezza
Categoria_lunghezza n Percentuale
Lunghezza bassa (≤ P10) 265 10.6%
Lunghezza nella norma (P10-P90) 1991 79.64%
Lunghezza elevata (> P90) 244 9.76%

Cranio

p10_cranio <- quantile(dati_neonati$Cranio, 0.10, na.rm = TRUE)
p90_cranio <- quantile(dati_neonati$Cranio, 0.90, na.rm = TRUE)

cranio_breaks <- c(-Inf, p10_cranio, p90_cranio, Inf)

cranio_labels <- c(
  "Circonferenza cranica bassa (≤ P10)",
  "Circonferenza cranica nella norma (P10-P90)",
  "Circonferenza cranica elevata (> P90)"
)

dati_neonati <- crea_categoria(
  dati_neonati,
  "Cranio",
  cranio_breaks,
  cranio_labels,
  "Categoria_cranio"
)

tabella_percentili <- data.frame(
  Statistica = c("P10 Cranio [mm]", "P90 Cranio [mm]"),
  Valore = c(p10_cranio, p90_cranio)
)

stampa_tabella(
  tabella_percentili,
  caption = "Percentili della lunghezza"
)
Percentili della lunghezza
Statistica Valore
10% P10 Cranio [mm] 320
90% P90 Cranio [mm] 360
stampa_tabella(
  tabella_frequenze(dati_neonati, "Categoria_cranio"),
  "Frequenze assolute e relative delle categorie cranio"
)
Frequenze assolute e relative delle categorie cranio
Categoria_cranio n Percentuale
Circonferenza cranica bassa (≤ P10) 252 10.08%
Circonferenza cranica nella norma (P10-P90) 2063 82.52%
Circonferenza cranica elevata (> P90) 185 7.4%

Analisi Lunghezza e Cranio

Lunghezza e Cranio:

  • Le categorie della lunghezza e cranio sono state definite utilizzando il 10° (10% delle osservazioni hanno un valore <=valore_rilevato) e il 90°(90% delle osservazioni hanno un valore <=valore_rilevato) percentile calcolati sul campione analizzato, al fine di distinguere neonati con lunghezza e diametro del cranio relativamente bassi, nella norma o elevata rispetto alla distribuzione osservata. La fonte dalla quale ho estratto le informazioni di classificazione è la seguente: https://www.ospedalebambinogesu.it/neonato-piccolo-per-eta-gestazionale-89920/. Questa metodologia è sufficiente ed è più facile da interpretare per questo progetto di Data Science. Tuttavia, sarebbe più corretto dal punto di vista clinico, usare le curve INTERGROWTH-21st o WHO e classifica Lunghezza, Peso e Cranio in SGA/AGA/LGA usando i percentili ufficiali in funzione di età gestazionale e sesso. Fonti:
  • il 90% dei neonati ha una lunghezza <=520mm ed un diametro del cranio <=360mm
  • il 10% dei neonati ha una lunghezza <=465mm ed un diametro del cranio <=320mm

Fumatrici

stampa_tabella(
  controlla_categorie(
    dati_neonati,
    "Fumatrici",
    c(0, 1)
  ),
  caption = "Controllo della variabile Fumatrici"
)
Controllo della variabile Fumatrici
Variabile Valori osservati Valori mancanti Valori non validi
Fumatrici 0, 1 0 Nessuno
dati_neonati$Fumatrici <- factor(
  dati_neonati$Fumatrici,
  levels = c(0, 1),
  labels = c("Non fumatrice", "Fumatrice")
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Fumatrici"),
  "Frequenze assolute e relative delle donne Fumatrici/Non Fumatrici"
)
Frequenze assolute e relative delle donne Fumatrici/Non Fumatrici
Fumatrici n Percentuale
Non fumatrice 2396 95.84%
Fumatrice 104 4.16%
#fumatrici
ggplot(dati_neonati, aes(x = Fumatrici, fill = Fumatrici)) +
  geom_bar() +
  labs(
    title = "Distribuzione delle madri fumatrici",
    x = "",
    y = "Frequenza"
  ) +
  theme_minimal()

# Fumatrici - peso
ggplot(dati_neonati,
       aes(Fumatrici, Peso, fill = Fumatrici)) +
  geom_boxplot()

Analisi Fumatrici

Fumatrici:

  • Non sono presenti valori mancanti o anomali
  • Quasi il 96% delle madri è non fumatrice
  • Il peso diminuisce se una madre è fumatrice. Questa ipotesi verrà verificata con opportuni test statistici

Tipo.parto

stampa_tabella(
  controlla_categorie(
    dati_neonati,
    "Tipo.parto",
    c("Nat", "Ces")
  ),
  caption = "Controllo della variabile Tipo.parto"
)
Controllo della variabile Tipo.parto
Variabile Valori osservati Valori mancanti Valori non validi
Tipo.parto Ces, Nat 0 Nessuno
dati_neonati$Tipo.parto <- factor(
  dati_neonati$Tipo.parto,
  levels = c("Nat", "Ces"),
  labels = c("Parto naturale", "Taglio cesareo")
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Tipo.parto"),
  "Frequenze assolute e relative del tipo parto"
)
Frequenze assolute e relative del tipo parto
Tipo.parto n Percentuale
Parto naturale 1772 70.88%
Taglio cesareo 728 29.12%
# Tipo parto-Peso
ggplot(dati_neonati,
       aes(Tipo.parto, Peso, fill = Tipo.parto)) +
  geom_boxplot()

Analisi Tipo.parto

Tipo.parto:

  • Non sono presenti valori mancanti o anomali
  • Quasi il 71% delle madri ha eseguito un parto naturale
  • il tipo di parto non sembra influenzare il peso del neonato
stampa_tabella(
  controlla_categorie(
    dati_neonati,
    "Ospedale",
    c("osp1", "osp2", "osp3")
  ),
  caption = "Controllo della variabile Ospedale"
)
Controllo della variabile Ospedale
Variabile Valori osservati Valori mancanti Valori non validi
Ospedale osp1, osp2, osp3 0 Nessuno
dati_neonati$Ospedale <- factor(
  dati_neonati$Ospedale,
  levels = c("osp1", "osp2", "osp3"),
  labels = c(
    "Ospedale 1",
    "Ospedale 2",
    "Ospedale 3"
  )
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Ospedale"),
  "Frequenze assolute e relative del tipo parto"
)
Frequenze assolute e relative del tipo parto
Ospedale n Percentuale
Ospedale 1 816 32.64%
Ospedale 2 849 33.96%
Ospedale 3 835 33.4%
#Ospedale-Peso
ggplot(dati_neonati,
       aes(Ospedale, Peso, fill = Ospedale)) +
  geom_boxplot()

Analisi Ospedale

Ospedale:

  • Non sono presenti valori mancanti o anomali
  • Il numero di neonati tra gli ospedali è equamente distribuito
  • I tre ospedali mostrano distribuzioni del peso molto simili, con mediane e intervalli interquartili confrontabili. La maggior parte dei neonati presenta un peso compreso tra circa 3000 g e 3600 g, mentre sono presenti alcuni valori estremi al di fuori di tale intervallo

Sesso

stampa_tabella(
  controlla_categorie(
    dati_neonati,
    "Sesso",
    c("M", "F")
  ),
  caption = "Controllo della variabile Sesso"
)
Controllo della variabile Sesso
Variabile Valori osservati Valori mancanti Valori non validi
Sesso F, M 0 Nessuno
dati_neonati$Sesso <- factor(
  dati_neonati$Sesso,
  levels = c("M", "F"),
  labels = c("Maschio", "Femmina")
)

stampa_tabella(
  tabella_frequenze(dati_neonati, "Sesso"),
  "Frequenze assolute e relative del Sesso"
)
Frequenze assolute e relative del Sesso
Sesso n Percentuale
Maschio 1244 49.76%
Femmina 1256 50.24%
# Sesso-Peso
ggplot(dati_neonati,
       aes(Sesso, Peso, fill = Sesso)) +
  geom_boxplot()

Analisi Sesso

Sesso:

  • Non sono presenti valori mancanti o anomali;
  • Il sesso maschile e femminile sono bilanciati (Quasi il 50% ciascuno)
  • Il peso potrebbe essere influenzato dal sesso. Nei soggetti maschili il peso è maggiore. Questa ipotesi sarà verificata in seguito con opportuni test statistici.

Riepilogo EDA

Dopo l’EDA verranno effettuati opportuni test statistici per verificare se le relazioni osservate durante l’analisi esplorativa risultano statisticamente significative e per individuare le variabili maggiormente associate al peso del neonato. In particolare saranno analizzate le seguenti ipotesi:

Infine, le variabili che risulteranno statisticamente significative saranno considerate come possibili predittori nella costruzione del modello di regressione per la previsione del peso del neonato.

Test Statistici

N.B. È opportuno considerare che i test parametrici risultano generalmente robusti a moderate violazioni dell’ipotesi di normalità grazie al Teorema del Limite Centrale.

N.B. Per tutti i test t vale:

Equivalentemente:

Pertanto, nei test viene confrontata la differenza tra la media osservata e quella ipotizzata.

Considerazioni sull’ANOVA Test

  • Si utilizza quando si vuole confrontare una variabile quantitativa con una variabile categorica avente più di due livelli, evitando di eseguire numerosi t-test. Infatti, confrontare tutte le coppie di gruppi mediante più t-test aumenterebbe la probabilità di commettere un errore di I tipo (falso positivo).
  • L’ANOVA non individua quale gruppo differisce dagli altri, ma verifica solamente se almeno una media è diversa.
  • L’ANOVA confronta due tipi di variabilità:
    • variabilità tra i gruppi;
    • variabilità all’interno dei gruppi.
  • Se la variabilità tra i gruppi è molto maggiore della variabilità interna ai gruppi, allora è probabile che le medie siano realmente differenti. La statistica del test è

\[ F=\frac{\text{variabilità tra i gruppi}}{\text{variabilità all'interno dei gruppi}} \]

  • Se il valore di \(F\) è vicino a 1, le due variabilità risultano simili e, di conseguenza, anche le medie dei gruppi tendono ad essere simili.
  • Se invece il valore di \(F\) è elevato, significa che almeno una media differisce dalle altre.

Fonti


1. In alcuni ospedali si effettuano più parti cesarei

Variabili

  • Ospedale (categorica)
  • Tipo.parto (categorica)

Entrambe le variabili sono qualitative; pertanto il test corretto è il test χ² di indipendenza.

Ipotesi

  • \(H_0\): il tipo di parto è indipendente dall’ospedale.
  • \(H_1\): esiste un’associazione tra ospedale e tipo di parto.
tabella <- table(
  dati_neonati$Ospedale,
  dati_neonati$Tipo.parto
)

stampa_tabella(
  cbind(
    Ospedale = rownames(tabella),
    as.data.frame.matrix(tabella)
  ),
  caption = "Tabella di contingenza tra ospedale e tipo di parto"
)
Tabella di contingenza tra ospedale e tipo di parto
Ospedale Parto naturale Taglio cesareo
Ospedale 1 Ospedale 1 574 242
Ospedale 2 Ospedale 2 595 254
Ospedale 3 Ospedale 3 603 232
stampa_tabella(
  cbind(
    Ospedale = rownames(tabella),
    as.data.frame.matrix(round(prop.table(tabella, margin = 1) * 100, 2))
  ),
  caption = "Distribuzione percentuale del tipo di parto per ospedale"
)
Distribuzione percentuale del tipo di parto per ospedale
Ospedale Parto naturale Taglio cesareo
Ospedale 1 Ospedale 1 70.34 29.66
Ospedale 2 Ospedale 2 70.08 29.92
Ospedale 3 Ospedale 3 72.22 27.78
test <- chisq.test(tabella)

stampa_tabella(
  cbind(
    Ospedale = rownames(test$expected),
    as.data.frame.matrix(round(test$expected, 2))
  ),
  caption = "Frequenze attese del test χ²"
)
Frequenze attese del test χ²
Ospedale Parto naturale Taglio cesareo
Ospedale 1 Ospedale 1 578.38 237.62
Ospedale 2 Ospedale 2 601.77 247.23
Ospedale 3 Ospedale 3 591.85 243.15
stampa_tabella(
  data.frame(
    `Statistica χ²` = round(unname(test$statistic), 2),
    `Gradi di libertà` = unname(test$parameter),
    `p-value` = signif(test$p.value, 4)
  ),
  caption = "Risultato del test χ²"
)
Risultato del test χ²
Statistica.χ. Gradi.di.libertà p.value
1.1 2 0.5778

Esito del test

Poiché il p-value (0.5778) è maggiore del livello di significatività (\(\alpha=0.05\)), non si rifiuta l’ipotesi nulla di indipendenza. Pertanto, nel campione analizzato, non vi sono evidenze statisticamente significative di un’associazione tra l’ospedale e il tipo di parto. In particolare, le differenze osservate nelle percentuali di parti cesarei tra i tre ospedali non risultano statisticamente significative e possono essere attribuite alla variabilità casuale del campione.


2. La media del peso e della lunghezza sono uguali a quelle della popolazione

Variabili

  • Peso (continua)
  • Lunghezza (continua)

È opportuno utilizzare un One Sample t-test.

Ipotesi

Peso:

  • \(H_0:\mu=3300\)
  • \(H_1:\mu\neq3300\)

Lunghezza:

  • \(H_0:\mu=500\)
  • \(H_1:\mu\neq500\)

Si considerano un peso medio pari a 3300 g e una lunghezza media pari a 500 mm, come valori di riferimento per la popolazione.

Fonte

https://www.ospedalebambinogesu.it/da-0-a-30-giorni-come-si-presenta-e-come-cresce-80012/

test_media(
  dati_neonati$Peso,
  "Peso",
  mu = 3300
)
One Sample t-test per Peso
Variabile Media campionaria Media ipotizzata Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Peso 3284.08 3300 -1.52 2499 0.13 3263.49 3304.67
test_media(
  dati_neonati$Lunghezza,
  "Lunghezza",
  mu = 500
)
One Sample t-test per Lunghezza
Variabile Media campionaria Media ipotizzata Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Lunghezza 494.69 500 -10.08 2499 <2e-16 493.66 495.72

Esito del test

Il One Sample t-test, considerando il peso, non ha evidenziato differenze statisticamente significative tra la media del campione (3284 g) e quella ipotizzata per la popolazione (3300 g) (\(t=-1.52\); \(p=0.130\)). Pertanto non si rifiuta l’ipotesi nulla.

Per quanto riguarda la lunghezza, la media campionaria risulta significativamente diversa da quella ipotizzata. Ciò è confermato anche dall’intervallo di confidenza, che non contiene il valore di riferimento pari a 500 mm. Tale conclusione è supportata dal p-value, ampiamente inferiore al livello di significatività.


3. Le misure antropometriche sono diverse tra i due sessi

Variabili

  • Peso (continua)
  • Lunghezza (continua)
  • Cranio (continua)
  • Sesso (categorica)

È opportuno utilizzare un t-test per campioni indipendenti (Welch).

Ipotesi

  • \(H_0:\mu_M=\mu_F\)
  • \(H_1:\mu_M\neq\mu_F\)
test_confronto_gruppi(
  Peso ~ Sesso,
  dati_neonati,
  "Peso"
)
Two Sample t-test per Peso
Variabile Gruppi Media gruppo 1 Media gruppo 2 Differenza medie Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Peso Maschio vs Femmina 3408.22 3161.13 -247.08 12.11 2490.72 <2e-16 207.06 287.11
test_confronto_gruppi(
  Lunghezza ~ Sesso,
  dati_neonati,
  "Lunghezza"
)
Two Sample t-test per Lunghezza
Variabile Gruppi Media gruppo 1 Media gruppo 2 Differenza medie Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Lunghezza Maschio vs Femmina 499.67 489.76 -9.9 9.58 2459.3 <2e-16 7.88 11.93
test_confronto_gruppi(
  Cranio ~ Sesso,
  dati_neonati,
  "Cranio"
)
Two Sample t-test per Cranio
Variabile Gruppi Media gruppo 1 Media gruppo 2 Differenza medie Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Cranio Maschio vs Femmina 342.45 337.63 -4.82 7.41 2491.39 1.7e-13 3.54 6.09

Esito del test

Peso

Il test t di Welch evidenzia una differenza statisticamente significativa tra il peso medio dei neonati maschi e quello delle femmine (\(t=12.11\); \(p<0.001\)). Si rifiuta quindi l’ipotesi nulla. In media, i neonati maschi pesano circa 247 g in più delle femmine (3408 g contro 3161 g). L’intervallo di confidenza al 95% della differenza è compreso tra 207 g e 287 g.

Lunghezza

Anche la lunghezza media differisce significativamente tra i due sessi (\(t=9.58\); \(p<0.001\)). Si rifiuta l’ipotesi nulla. I neonati maschi risultano mediamente più lunghi di circa 10 mm rispetto alle femmine.

Cranio

Il diametro medio del cranio è significativamente maggiore nei maschi rispetto alle femmine (\(t=7.41\); \(p<0.001\)). Anche in questo caso si rifiuta l’ipotesi nulla.

Conclusione

Le misure antropometriche considerate (peso, lunghezza e circonferenza cranica) risultano significativamente maggiori nei neonati di sesso maschile rispetto a quelli di sesso femminile.


4. Il peso varia se una madre è fumatrice o meno

Variabili

  • Fumatrici (categorica)
  • Peso (continua)

È opportuno utilizzare un t-test per campioni indipendenti.

Ipotesi

  • \(H_0:\mu_F=\mu_{NF}\)
  • \(H_1:\mu_F\neq\mu_{NF}\)
test_confronto_gruppi(
  Peso ~ Fumatrici,
  dati_neonati,
  "Fumatrici"
)
Two Sample t-test per Fumatrici
Variabile Gruppi Media gruppo 1 Media gruppo 2 Differenza medie Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Fumatrici Non fumatrice vs Fumatrice 3286.15 3236.35 -49.81 1.03 114.1 0.3 -45.61 145.23

Esito del test

Il test t di Welch non evidenzia una differenza statisticamente significativa tra il peso medio dei neonati di madri fumatrici e quello dei neonati di madri non fumatrici (\(t=1.03\); \(p=0.303\)). Pertanto non si rifiuta l’ipotesi nulla. Sebbene il peso medio dei figli di madri non fumatrici sia leggermente superiore (3286 g contro 3236 g), tale differenza non risulta statisticamente significativa.


5. Il peso varia tra le classi di tipo di parto

Variabili

  • Tipo.parto (categorica)
  • Peso (continua)

È opportuno utilizzare un t-test per campioni indipendenti.

Ipotesi

  • \(H_0:\mu_N=\mu_C\)
  • \(H_1:\mu_N\neq\mu_C\)
test_confronto_gruppi(
  Peso ~ Tipo.parto,
  dati_neonati,
  "Tipo.parto"
)
Two Sample t-test per Tipo.parto
Variabile Gruppi Media gruppo 1 Media gruppo 2 Differenza medie Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Tipo.parto Parto naturale vs Taglio cesareo 3284.92 3282.05 -2.87 0.13 1492.96 0.9 -40.54 46.28

Esito del test

Il test t di Welch non evidenzia differenze statisticamente significative tra il peso medio dei neonati nati mediante parto naturale e quello dei neonati nati mediante taglio cesareo (\(t=0.13\); \(p=0.897\)). Pertanto non si rifiuta l’ipotesi nulla e non vi sono evidenze che il tipo di parto influenzi il peso alla nascita.


6. Il peso varia tra le classi di età materna

Variabili

  • Categorie_Anni_Madre (categorica)
  • Peso (continua)

È opportuno utilizzare un One-Way ANOVA.

Ipotesi

  • \(H_0:\mu_{Adolescente}=\mu_{20-24}=\mu_{25-29}=\mu_{30-34}=\mu_{\ge35}\)
  • \(H_1:\) almeno una delle medie è diversa.
test_anova(
  Peso ~ Categorie_Anni_Madre,
  dati_neonati,
  "Peso rispetto alle categorie di età materna"
)
ANOVA a una via per Peso rispetto alle categorie di età materna
Fonte Gradi liberta Somma quadrati Media quadratica Statistica F p-value
Categorie_Anni_Madre 4 1877665 469416.2 1.7 0.1461
Residuals 2495 687010877 275355.1 NA NA

Esito del test

L’ANOVA non evidenzia differenze statisticamente significative del peso medio tra le diverse classi di età materna (\(F=1.705\); \(p=0.146\)). Pertanto non si rifiuta l’ipotesi nulla e non vi sono evidenze che il peso medio del neonato vari significativamente in funzione della fascia di età della madre. Ciò è coerente con il fatto che la variabilità all’interno dei gruppi risulta maggiore della variabilità tra i gruppi e con il p-value superiore al livello di significatività.


7. Il peso dei neonati varia tra gli ospedali

Variabili

  • Ospedale (categorica)
  • Peso (continua)

È opportuno utilizzare un One-Way ANOVA.

Ipotesi

  • \(H_0:\mu_A=\mu_B=\mu_C\)
  • \(H_1:\) almeno una media differisce dalle altre.
test_anova(
  Peso ~ Ospedale,
  dati_neonati,
  "Peso rispetto agli Ospedali di nascita"
)
ANOVA a una via per Peso rispetto agli Ospedali di nascita
Fonte Gradi liberta Somma quadrati Media quadratica Statistica F p-value
Ospedale 2 936236.8 468118.4 1.7 0.1831
Residuals 2497 687952304.9 275511.5 NA NA

Esito del test

L’ANOVA è stata applicata per confrontare il peso medio dei neonati nei tre ospedali. Il test non è risultato statisticamente significativo (\(F=1.699\); \(p=0.183\)). Pertanto non si rifiuta l’ipotesi nulla e non emergono differenze significative tra gli ospedali.


8. Il numero di settimane di gestazione è correlato al peso del neonato

Variabili

  • Gestazione (discreta)
  • Peso (continua)

È opportuno utilizzare il test di correlazione di Pearson, che restituisce un coefficiente compreso tra:

  • -1: massima correlazione negativa;
  • 0: assenza di correlazione;
  • +1: massima correlazione positiva.

Ipotesi

  • \(H_0:\rho=0\)
  • \(H_1:\rho\neq0\)
test_correlazione(
  dati_neonati$Peso,
  dati_neonati$Gestazione,
  "Peso",
  "Gestazione"
)
Correlazione di Pearson tra Peso e Gestazione
Variabile_1 Variabile_2 Coefficiente Pearson (r) Statistica t Gradi liberta p-value IC 95% inferiore IC 95% superiore
Peso Gestazione 0.59 36.69 2498 <2e-16 0.57 0.62

Esito del test

Il test di correlazione di Pearson evidenzia una correlazione positiva moderata e statisticamente significativa tra la durata della gestazione e il peso alla nascita (\(r=0.592\); \(p<0.001\)). Pertanto si rifiuta l’ipotesi nulla di assenza di correlazione. All’aumentare delle settimane di gestazione tende ad aumentare anche il peso del neonato.

Riepilogo dei test statistici

Nel complesso, i test statistici univariati evidenziano che le variabili Gestazione e Sesso sono quelle maggiormente associate al peso alla nascita, mostrando un’associazione statisticamente significativa con la variabile risposta.

Al contrario, le variabili Anni della madre, Fumatrici, Tipo di parto e Ospedale non risultano statisticamente significative nelle analisi univariate. Tuttavia, tale risultato non implica necessariamente che queste variabili debbano essere escluse dal modello di regressione multipla. Infatti, una variabile può non mostrare un effetto significativo se considerata singolarmente, ma contribuire in modo rilevante quando viene analizzata congiuntamente alle altre variabili esplicative, oppure migliorare la capacità predittiva complessiva del modello.

Per questo motivo, la selezione finale delle variabili è stata effettuata mediante regressione lineare multipla.

Creazione del Modello di Regressione

Strategia

Dopo aver ottenuto il modello finale mediante selezione automatica delle variabili, la sua capacità predittiva è stata valutata attraverso il coefficiente di determinazione R^2, il coefficiente di determinazione aggiustato e il Root Mean Squared Error (RMSE), che misura l’errore medio di previsione espresso in grammi. Successivamente sono state verificate le principali ipotesi della regressione lineare mediante l’analisi grafica dei residui (residui vs valori predetti, Q-Q Plot e Scale-Location Plot). Infine, sono stati individuati eventuali valori influenti tramite la distanza di Cook, il leverage e i residui standardizzati, valutando se alcune osservazioni potessero esercitare un’influenza eccessiva sulla stima dei coefficienti del modello. Inoltre, la presenza di multicollinearità tra le variabili esplicative è stata verificata mediante il Variance Inflation Factor (VIF).


Valutazione del modello Baseline di regressione lineare

È stato inizialmente costruito un modello di regressione lineare multipla (modello_baseline) considerando tutte le variabili disponibili per spiegare il peso neonatale:

\[ Peso \sim Anni.madre + N.gravidanze + Fumatrici + Gestazione + Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso \]

Il modello completo ha ottenuto:

  • R² = 0.7289
  • R² corretto = 0.7278
  • RMSE = 273.9 g

Il coefficiente di determinazione indica che circa il 72.9% della variabilità del peso alla nascita è spiegata dalle variabili considerate, mentre il restante 27% è attribuibile ad altri fattori non presenti nel dataset o alla variabilità naturale del fenomeno biologico.

L’errore medio di previsione, espresso tramite RMSE, è pari a circa 273 grammi, valore contenuto considerando la variabilità fisiologica del peso neonatale.

Coefficienti del modello di regressione baseline
Variabile Estimate Std. Error t value Pr(>&#124;t&#124;)
(Intercept) -6628.12 142.92 -46.38 0.00
Anni.madre 0.80 1.15 0.70 0.49
N.gravidanze 11.41 4.67 2.45 0.01
FumatriciFumatrice -30.16 27.54 -1.10 0.27
Gestazione 32.53 3.82 8.52 0.00
Lunghezza 10.30 0.30 34.24 0.00
Cranio 10.47 0.43 24.58 0.00
Tipo.partoTaglio cesareo -29.50 12.08 -2.44 0.01
OspedaleOspedale 2 -11.22 13.44 -0.84 0.40
OspedaleOspedale 3 28.10 13.50 2.08 0.04
SessoFemmina -77.55 11.18 -6.94 0.00
Statistiche di sintesi del modello baseline
Statistica Valore
R quadro 0.73
R quadro corretto 0.73
F statistic 669.14
p-value globale < 2.2e-16

Analisi dei coefficienti

Dall’analisi dei coefficienti del modello completo emergono alcune variabili con un effetto statisticamente significativo sul peso.

Le variabili che mostrano un’associazione positiva con il peso sono:

  • Gestazione: ogni settimana aggiuntiva di gestazione determina un incremento medio stimato del peso di circa 32 g, mantenendo costanti le altre variabili.

  • Lunghezza: rappresenta uno dei principali predittori del peso; un aumento della lunghezza neonatale è associato ad un incremento del peso stimato.

  • Cranio: anche la circonferenza cranica mostra un effetto positivo significativo, indicando una relazione tra sviluppo corporeo e peso alla nascita.

  • Numero di gravidanze precedenti: presenta un effetto positivo ma più contenuto.

Per quanto riguarda le variabili categoriche:

  • Il parto cesareo presenta un coefficiente negativo rispetto al parto naturale, con una riduzione stimata del peso di circa 29 g.

  • Il sesso femminile mostra un coefficiente negativo significativo, con un peso medio stimato inferiore di circa 77 g rispetto al sesso maschile.

  • La variabile Ospedale mostra differenze significative solamente per l’Ospedale 3, mentre l’Ospedale 2 non risulta statisticamente diverso rispetto alla categoria di riferimento.

Al contrario, l’età della madre e il fumo durante la gravidanza non risultano statisticamente significativi nel modello completo.

Selezione del modello tramite AIC

E’ stata applicata una procedura di selezione automatica basata sull’AIC (stepAIC), ottenendo un modello più parsimonioso:

[ Peso N.gravidanze + Gestazione + Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso]

Sono state quindi eliminate:

  • Anni.madre
  • Fumatrici

poiché il loro contributo non risultava sufficiente a migliorare il compromesso tra complessità e capacità esplicativa del modello.

Il modello finale mantiene praticamente le stesse prestazioni:

Modello R² R² corretto
Completo 0.7289 0.7278
AIC 0.7287 0.7278

La perdita di capacità predittiva è trascurabile, mentre il modello risulta più semplice e maggiormente interpretabile.

Matrice di correlazione delle variabili numeriche nel modello finale
Peso N.gravidanze Gestazione Lunghezza Cranio
Peso 1.00 0.00 0.59 0.80 0.70
N.gravidanze 0.00 1.00 -0.10 -0.06 0.04
Gestazione 0.59 -0.10 1.00 0.62 0.46
Lunghezza 0.80 -0.06 0.62 1.00 0.60
Cranio 0.70 0.04 0.46 0.60 1.00
Coefficienti del modello di regressione finale (dopo stepAIC)
Variabile Estimate Std. Error t value Pr(>&#124;t&#124;)
(Intercept) -6600.71 137.49 -48.01 0.00
N.gravidanze 12.36 4.33 2.85 0.00
Gestazione 31.99 3.79 8.44 0.00
Lunghezza 10.31 0.30 34.32 0.00
Cranio 10.49 0.43 24.66 0.00
Tipo.partoTaglio cesareo -29.28 12.08 -2.42 0.02
OspedaleOspedale 2 -11.02 13.44 -0.82 0.41
OspedaleOspedale 3 28.64 13.49 2.12 0.03
SessoFemmina -77.44 11.18 -6.93 0.00
Statistiche di sintesi del modello finale
Statistica Valore
R quadro 0.73
R quadro corretto 0.73
AIC 35169.79
RMSE 273.42

Analisi dei residui e diagnostica del modello

Residuals vs Fitted

La maggior parte dei residui è distribuita attorno allo zero senza una struttura evidente. La linea di smoothing rimane vicina alla linea orizzontale, suggerendo una relazione prevalentemente lineare tra variabili esplicative e peso.

Sono tuttavia presenti alcuni valori estremi, in particolare l’osservazione 1551, caratterizzata da un residuo molto elevato.


Q-Q plot

Il grafico Q-Q mostra una buona aderenza dei residui alla distribuzione normale nella parte centrale.

Si osservano però deviazioni nelle code, soprattutto nella parte superiore, dovute alla presenza di alcuni neonati con peso molto superiore rispetto alla previsione del modello.

Questi punti rappresentano possibili outlier biologici e non necessariamente errori nei dati.


Scale-Location e Residui Standardizzati

Il grafico dei residui standardizzati rispetto all’indice mostra una distribuzione casuale dei residui attorno allo zero, senza evidenti pattern sistematici. La quasi totalità delle osservazioni rientra nell’intervallo ±3, sebbene siano presenti pochi outlier con residui standardizzati elevati. Dunque, non emerge una marcata eteroschedasticità, anche se per valori estremi del peso si osserva una maggiore variabilità.

Ho applicato la radice quadrata ai residui perchè questa trasformazione rende più facile valutare la variabilità dei residui. Il grafico Scale-Location evidenzia una dispersione dei residui sostanzialmente costante lungo l’intervallo dei valori predetti. La linea di smoothing risulta pressoché orizzontale, suggerendo che l’ipotesi di omoschedasticità sia ragionevolmente soddisfatta, pur in presenza di una lieve crescita della variabilità per valori predetti più elevati e di alcune osservazioni anomale


Residuals vs Leverage e Cook’s Distance

Osservazioni influenti secondo la distanza di Cook (soglia 4/n)
Indice osservazione
13 13
34 34
119 119
130 130
134 134
140 140
146 146
155 155
161 161
220 220
274 274
295 295
310 310
329 329
375 375
377 377
390 390
455 455
472 472
478 478
516 516
582 582
615 615
616 616
632 632
633 633
648 648
656 656
657 657
684 684
791 791
805 805
828 828
890 890
908 908
928 928
950 950
1008 1008
1014 1014
1036 1036
1130 1130
1132 1132
1137 1137
1181 1181
1188 1188
1192 1192
1194 1194
1212 1212
1230 1230
1253 1253
1267 1267
1268 1268
1273 1273
1287 1287
1293 1293
1306 1306
1317 1317
1341 1341
1395 1395
1399 1399
1402 1402
1426 1426
1429 1429
1433 1433
1450 1450
1472 1472
1499 1499
1505 1505
1541 1541
1551 1551
1553 1553
1556 1556
1588 1588
1593 1593
1619 1619
1635 1635
1639 1639
1694 1694
1702 1702
1712 1712
1718 1718
1780 1780
1838 1838
1856 1856
1868 1868
1893 1893
1915 1915
1920 1920
1926 1926
1937 1937
1962 1962
1963 1963
2023 2023
2040 2040
2076 2076
2086 2086
2114 2114
2115 2115
2120 2120
2123 2123
2135 2135
2175 2175
2195 2195
2204 2204
2219 2219
2221 2221
2225 2225
2287 2287
2315 2315
2317 2317
2392 2392
2421 2421
2422 2422
2437 2437
2452 2452
2471 2471

Il grafico evidenzia alcune osservazioni influenti:

  • osservazione 1551
  • osservazione 310

In particolare l’osservazione 1551 presenta un’elevata distanza di Cook, indicando una possibile influenza sul modello.

Tuttavia, considerando la dimensione del campione (2500 osservazioni), tali punti non sembrano compromettere significativamente la validità complessiva del modello.

Analisi di Outliers

Caratteristiche dell’osservazione 1551
Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto Ospedale Sesso
1551 35 1 Non fumatrice 38 4370 315 374 Parto naturale Ospedale 3 Femmina
Confronto del modello con e senza l’osservazione 1551
Modello R2 R2_corretto AIC RMSE
Modello completo 0.73 0.73 35169.79 273.42
Senza osservazione 1551 0.74 0.74 35058.25 268.14
Confronto dei coefficienti stimati
Coefficiente Completo Senza_1551
(Intercept) (Intercept) -6600.71 -6602.01
N.gravidanze N.gravidanze 12.36 13.07
Gestazione Gestazione 31.99 29.29
Lunghezza Lunghezza 10.31 10.95
Cranio Cranio 10.49 9.88
Tipo.partoTaglio cesareo Tipo.partoTaglio cesareo -29.28 -29.19
OspedaleOspedale 2 OspedaleOspedale 2 -11.02 -11.69
OspedaleOspedale 3 OspedaleOspedale 3 28.64 25.43
SessoFemmina SessoFemmina -77.44 -77.61

L’osservazione 1551 è stata ulteriormente analizzata in quanto presenta la maggiore distanza di Cook. L’analisi delle caratteristiche del neonato non suggerisce la presenza di errori di inserimento dei dati. Inoltre, il ricalcolo del modello dopo l’esclusione dell’osservazione non produce variazioni sostanziali nei coefficienti stimati né nelle principali misure di bontà di adattamento. Pertanto, l’osservazione è stata mantenuta nell’analisi, in quanto rappresenta un caso influente ma plausibile dal punto di vista biologico.

Analisi di multicollinearità con VIF

Variance Inflation Factor (VIF/GVIF) del modello finale
Variabile GVIF Df GVIF^(1/(2*Df))
N.gravidanze 1.03 1 1.01
Gestazione 1.67 1 1.29
Lunghezza 2.08 1 1.44
Cranio 1.63 1 1.28
Tipo.parto 1.00 1 1.00
Ospedale 1.00 2 1.00
Sesso 1.04 1 1.02

Per verificare la presenza di ridondanza tra i predittori è stata analizzata la matrice di correlazione e successivamente calcolato il VIF.

La matrice di correlazione mostra:

  • Peso - Lunghezza: r = 0.80
  • Peso - Cranio: r = 0.70
  • Peso - Gestazione: r = 0.59

Queste correlazioni sono coerenti dal punto di vista biologico, poiché neonati con maggiore sviluppo fetale tendono ad avere peso maggiore.

Le correlazioni tra variabili esplicative risultano invece moderate:

  • Lunghezza - Cranio: r = 0.60
  • Gestazione - Lunghezza: r = 0.62
  • Gestazione - Cranio: r = 0.46

L’analisi VIF ha confermato l’assenza di multicollinearità:

  • VIF massimo per Lunghezza: circa 2.1 nel modello completo
  • tutti i valori risultano inferiori alla soglia critica di 5

Pertanto non è stato necessario eliminare variabili antropometriche come Lunghezza o Cranio, poiché entrambe forniscono informazioni indipendenti utili alla previsione del peso.

Confronto tra modelli

Sono stati valutati alcuni modelli alternativi con l’obiettivo di migliorare le prestazioni predittive. In particolare, è stata introdotta una spline naturale per modellare un possibile effetto non lineare della durata della gestazione. Per modellare eventuali relazioni non lineari tra la durata della gestazione e il peso neonatale è stata utilizzata una natural cubic spline, implementata tramite la funzione ns() del package splines di R. Tale funzione costruisce automaticamente una base di spline cubiche naturali, ossia polinomi cubici a tratti raccordati nei nodi con continuità della funzione e delle sue prime due derivate, imponendo inoltre linearità oltre i nodi estremi.

L’introduzione di una spline naturale non ha evidenziato un miglioramento significativo delle prestazioni del modello, suggerendo che la relazione tra durata della gestazione e peso neonatale risulta approssimativamente lineare nell’intervallo osservato.

Sono stati testati due modelli comprendenti termini di interazione tra le variabili:

  • Gestazione × Lunghezza, per verificare se l’effetto della lunghezza sul peso variasse in funzione della durata della gravidanza;

  • Gestazione × Sesso, per valutare eventuali differenze nello sviluppo fetale tra maschi e femmine.

Nessuno di questi modelli ha prodotto un miglioramento significativo delle prestazioni in termini di capacità esplicativa e accuratezza predittiva rispetto al modello lineare. Per tale motivo si è preferito adottare un modello di regressione lineare più semplice e interpretabile, successivamente ottimizzato mediante il criterio AIC, che ha consentito di eliminare le variabili meno significative mantenendo pressoché inalterate le prestazioni del modello.

Confronto tra i modelli di regressione (Baseline, Spline, Interazioni)
Modello R2 R2_corretto AIC RMSE
Baseline 0.73 0.73 35172.09 273.33
Spline 0.73 0.73 35164.97 272.72
Interazione Gestazione:Lunghezza 0.73 0.73 35148.38 271.93
Interazione Gestazione:Sesso 0.73 0.73 35172.44 273.24

Considerazioni

Nessuno di questi modelli ha prodotto un miglioramento significativo delle prestazioni in termini di capacità esplicativa e accuratezza predittiva rispetto al modello lineare. Per tale motivo si è preferito adottare un modello di regressione lineare più semplice e interpretabile, successivamente ottimizzato mediante il criterio AIC, che ha consentito di eliminare le variabili meno significative mantenendo pressoché inalterate le prestazioni del modello.

Predizioni

Caratteristiche del nuovo neonato utilizzato per la previsione
Anni.madre N.gravidanze Fumatrici Gestazione Lunghezza Cranio Tipo.parto Ospedale Sesso
30 2 Non fumatrice 39 500 340 Parto naturale Ospedale 1 Femmina
## Peso previsto per il nuovo neonato: 3316 grammi
Intervallo di previsione al 95% del peso neonatale
fit lwr upr
3315.88 2778.17 3853.6

Le variabili che influenzano maggiormente il peso alla nascita sono:

Possibili miglioramenti futuri

Sebbene il modello lineare abbia ottenuto buone prestazioni (R² ≈ 0.73 e RMSE ≈ 273 g), il restante errore di previsione suggerisce la presenza di relazioni più complesse non completamente catturate dalla regressione lineare.

Possibili miglioramenti futuri potrebbero includere:

1. Trasformazioni non lineari

È stata valutata la possibilità di modellare relazioni non lineari tra la variabile risposta e i predittori mediante l’impiego di spline naturali. Tuttavia, tale approccio non ha evidenziato miglioramenti significativi nelle prestazioni del modello rispetto alla regressione lineare.

Poiché le spline rappresentano una classe di modelli sufficientemente flessibile per descrivere eventuali effetti non lineari, ulteriori trasformazioni della stessa natura (ad esempio termini quadratici) difficilmente apporterebbero benefici rilevanti.


2. Modelli più flessibili

Per migliorare esclusivamente la capacità predittiva potrebbero essere confrontati modelli non lineari come:

  • Random Forest
  • Gradient Boosting
  • XGBoost

Tuttavia, la regressione lineare rimane preferibile perchè è meglio garantire una migliore interpretazione dei risultati del modello.


Conclusione

Il modello finale rappresenta un buon compromesso tra interpretabilità e capacità predittiva. La selezione tramite AIC ha permesso di ottenere un modello più semplice senza perdita significativa di performance. Le variabili antropometriche del neonato e la durata della gestazione risultano i principali fattori associati al peso alla nascita. Il modello, in presenza di nuovi dati, predice con una buona accuratezza il peso di un neonato. Questo viene evidenziato dal grafico “Peso Reale dei neonati e previsione del modello”.

Eventuali miglioramenti delle prestazioni del modello saranno ricercati mediante l’impiego di modelli non lineari, in grado di catturare meglio le relazioni e le interazioni tra le variabili.