Librerie

Importo le librerie necessarie allo sviluppo corretto dello studio

library(moments)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(tidyr)
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
library(MASS)
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(ggpubr)

Importo il dataset cosi da poter iniziare le varie analisi

neonati <- read.csv("neonati.csv", sep = ",")
str(neonati)
## 'data.frame':    2500 obs. of  10 variables:
##  $ Anni.madre  : int  26 21 34 28 20 32 26 25 22 23 ...
##  $ N.gravidanze: int  0 2 3 1 0 0 1 0 1 0 ...
##  $ Fumatrici   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Gestazione  : int  42 39 38 41 38 40 39 40 40 41 ...
##  $ Peso        : int  3380 3150 3640 3690 3700 3200 3100 3580 3670 3700 ...
##  $ Lunghezza   : int  490 490 500 515 480 495 480 510 500 510 ...
##  $ Cranio      : int  325 345 375 365 335 340 345 349 335 362 ...
##  $ Tipo.parto  : chr  "Nat" "Nat" "Nat" "Nat" ...
##  $ Ospedale    : chr  "osp3" "osp1" "osp2" "osp2" ...
##  $ Sesso       : chr  "M" "F" "M" "M" ...

Analisi preliminare statistiche descrittive

Prima di procedere con l’analisi inferenziale, è fondamentale esplorare le caratteristiche principali delle variabili numeriche attraverso un’analisi descrittiva. Questo passaggio iniziale permette di ottenere una visione d’insieme della distribuzione dei dati, evidenziando:

Tali informazioni sono essenziali per comprendere la natura dei dati e individuare eventuali anomalie o outlier. Inoltre, le statistiche descrittive offrono indicazioni utili per orientare la scelta delle tecniche inferenziali più adeguate e per facilitare l’interpretazione dei risultati del successivo modello predittivo.

summary_stats <- function(x) {
  c(
    Media = round(mean(x, na.rm = TRUE), 2),
    Mediana = round(median(x, na.rm = TRUE), 2),
    Varianza = round(var(x, na.rm = TRUE), 2),
    Deviazione_Std = round(sd(x, na.rm = TRUE), 2),
    Coeff_Variazione = round((sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE)) * 100, 2),
    Asimmetria = round(skewness(x, na.rm = TRUE), 2),
    Curtosi = round(kurtosis(x, na.rm = TRUE), 2)
  )
}

numerical_vars <- neonati[, c("Anni.madre", "N.gravidanze", "Gestazione", "Peso", "Lunghezza", "Cranio")]
stats <- apply(numerical_vars, 2, summary_stats)
print(stats)
##                  Anni.madre N.gravidanze Gestazione      Peso Lunghezza Cranio
## Media                 28.16         0.98      38.98   3284.08    494.69 340.03
## Mediana               28.00         1.00      39.00   3300.00    500.00 340.00
## Varianza              27.81         1.64       3.49 275665.68    692.67 269.79
## Deviazione_Std         5.27         1.28       1.87    525.04     26.32  16.43
## Coeff_Variazione      18.72       130.51       4.79     15.99      5.32   4.83
## Asimmetria             0.04         2.51      -2.07     -0.65     -1.51  -0.79
## Curtosi                3.38        13.99      11.26      5.03      9.49   5.95

Le statistiche descrittive evidenziano una distribuzione generalmente regolare per la maggior parte delle variabili numeriche, con valori medi e mediani molto simili, variabilità contenuta e modesta asimmetria.

Le variabili Lunghezza e Cranio mostrano una variabilità molto bassa, mentre Gestazione presenta la variabilità maggiore; l’analisi di variabilità è stata condotta considerando il Coefficiente di Variazione per poter eliminare l’influenza dovuta a differenti ordini di grandezza (es: Peso e Lunghezza).

La variabile Gestazione è fortemente asimmetrica a sinistra, e N.gravidanze a destra, richiedendo attenzione nelle fasi inferenziali successive. La curtosi elevata in alcune variabili suggerisce la presenza di code pesanti, ma nel complesso i dati appaiono idonei all’applicazione di test parametrici e modelli lineari, che verranno approfonditi nelle sezioni successive.

freq_table_fun <- function(var) {
  tabella <- table(var)
  totale <- sum(tabella)
  freq_rel <- tabella / totale
  freq_cum <- cumsum(tabella)
  freq_rel_cum <- cumsum(freq_rel)
  
  cbind(
    Frequenza_Assoluta = as.vector(tabella),
    Frequenza_Relativa = round(freq_rel, 4),
    Frequenza_Cumulata = freq_cum,
    Freq_Relativa_Cumulata = round(freq_rel_cum, 4)
  )
}

freq_table_fumo <- freq_table_fun(neonati$Fumatrici)
rownames(freq_table_fumo) <- names(table(neonati$Fumatrici))
print(freq_table_fumo)
##   Frequenza_Assoluta Frequenza_Relativa Frequenza_Cumulata
## 0               2396             0.9584               2396
## 1                104             0.0416               2500
##   Freq_Relativa_Cumulata
## 0                 0.9584
## 1                 1.0000
freq_table_sesso <- freq_table_fun(neonati$Sesso)
rownames(freq_table_sesso) <- names(table(neonati$Sesso))
print(freq_table_sesso)
##   Frequenza_Assoluta Frequenza_Relativa Frequenza_Cumulata
## F               1256             0.5024               1256
## M               1244             0.4976               2500
##   Freq_Relativa_Cumulata
## F                 0.5024
## M                 1.0000
freq_table_parto <- freq_table_fun(neonati$Tipo.parto)
rownames(freq_table_parto) <- names(table(neonati$Tipo.parto))
print(freq_table_parto)
##     Frequenza_Assoluta Frequenza_Relativa Frequenza_Cumulata
## Ces                728             0.2912                728
## Nat               1772             0.7088               2500
##     Freq_Relativa_Cumulata
## Ces                 0.2912
## Nat                 1.0000
freq_table_ospedale <- freq_table_fun(neonati$Ospedale)
rownames(freq_table_ospedale) <- names(table(neonati$Ospedale))
print(freq_table_ospedale)
##      Frequenza_Assoluta Frequenza_Relativa Frequenza_Cumulata
## osp1                816             0.3264                816
## osp2                849             0.3396               1665
## osp3                835             0.3340               2500
##      Freq_Relativa_Cumulata
## osp1                 0.3264
## osp2                 0.6660
## osp3                 1.0000

Analisi delle Variabili Categoriali

L’esplorazione delle variabili categoriali evidenzia alcune caratteristiche rilevanti per le successive analisi inferenziali:

Sebbene alcune variabili mostrino una distribuzione sbilanciata, la numerosità dei sottogruppi resta generalmente sufficiente per supportare analisi comparative attendibili nel contesto inferenziale.

Boxplot

ggplot(neonati, aes(x = factor(Fumatrici), y = Peso, fill = factor(Fumatrici))) +
  geom_boxplot() +
  labs(
    title = "Distribuzione del Peso alla Nascita per Fumatrici",
    x = "Fumatrici (0 = No, 1 = Sì)",
    y = "Peso alla Nascita (g)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

Il boxplot mostra una differenza evidente tra i due gruppi:

Questo grafico conferma visivamente l’effetto negativo del fumo materno sul peso neonatale, coerente con le ipotesi e la letteratura esistente.

Istogramma

ggplot(neonati, aes(x = Peso)) +
  geom_histogram(binwidth = 250, fill = "skyblue", color = "black") +
  labs(
    title = "Distribuzione del Peso alla Nascita",
    x = "Peso (g)",
    y = "Frequenza"
  ) +
  theme_minimal()

L’istogramma mostra che la distribuzione del peso neonatale è approssimativamente normale, con una leggera asimmetria negativa, confermata dal coefficiente di asimmetria pari a circa -0.65.

Scatterplot

ggplot(neonati, aes(x = Gestazione, y = Peso)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "blue") +
  labs(
    title = "Peso alla Nascita in Funzione delle Settimane di Gestazione",
    x = "Settimane di Gestazione",
    y = "Peso alla Nascita (g)"
  ) +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

Lo scatterplot mette in evidenza una forte correlazione positiva e lineare tra settimane di gestazione e peso alla nascita

Questi risultati supportano l’ipotesi di una relazione lineare significativa tra durata della gestazione e peso alla nascita.

TEST PARAMETRICI

Test (1): In alcuni ospedali si fanno più parti cesarei

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


test_chi <- chisq.test(tabella)


test_chi$statistic     
## X-squared 
##  1.097202
test_chi$p.value       
## [1] 0.5777576
test_chi$expected      
##       
##             Ces      Nat
##   osp1 237.6192 578.3808
##   osp2 247.2288 601.7712
##   osp3 243.1520 591.8480
cat(sprintf(
  "Test chi-quadro: p-value = %.4f\n",
  test_chi$p.value
))
## Test chi-quadro: p-value = 0.5778

Non si riscontra una relazione statisticamente significativa tra l’ospedale di appartenenza e il tipo di parto (p = 0.5778). Pertanto, si mantiene l’ipotesi nulla di indipendenza: la distribuzione dei tipi di parto sembra essere simile tra i diversi ospedali del campione analizzato.

Questo risultato è confermato anche tramite analisi grafica, come evidenziato nei grafici sotto riportati.

ggballoonplot(as.data.frame(tabella), x = "Var1", y = "Var2", size = "Freq", fill = "blue") +
  labs(title = "Distribuzione Tipo di Parto per Ospedale",
       x = "Ospedale", y = "Tipo di Parto")

La visualizzazione della tabella di contingenza mostra chiaramente che in ciascun ospedale (osp1, osp2, osp3) il parto naturale (Nat) è largamente prevalente rispetto al cesareo (Ces). Le bolle corrispondenti ai parti naturali sono grandi e simili tra i tre ospedali, indicando frequenze elevate e comparabili. Al contrario, bolle dei cesarei mostrano frequenze basse e relativamente stabili tra gli ospedali.

curve(dchisq(x, df = test_chi$parameter), 
      from = 0, 
      to = max(30, test_chi$statistic + 10), 
      col = "blue", 
      lwd = 2,
      main = "Distribuzione Chi-quadro sotto H0",
      xlab = "Valori della statistica chi-quadro",
      ylab = "Densità")

abline(v = qchisq(0.95, df = test_chi$parameter), col = "red", lwd = 2, lty = 2)
points(test_chi$statistic, 0, col = "darkgreen", pch = 19, cex = 2)

legend("topright",
       legend = c("Distribuzione sotto H0", 
                  "Valore soglia (α=0.05)", 
                  "Statistica osservata"),
       col = c("blue", "red", "darkgreen"),
       lwd = c(2, 2, NA),
       lty = c(1, 2, NA),
       pch = c(NA, NA, 19))

Il test chi-quadro (X² = 1.097, p = 0.578) conferma l’indipendenza tra ospedale e tipo di parto. La statistica osservata (pallino verde) resta ampiamente sotto la soglia critica (linea rossa), non fornendo evidenze di associazione significativa tra le variabili.

Test (2): La media del peso e della lunghezza di questo campione di neonati sono significativamente uguali a quelle della popolazione

Per la costruzione dei test statistici, è particolarmente utile disporre di valori di riferimento noti per la media e la deviazione standard delle variabili peso e lunghezza neonatale. Da una rapida ricerca online emerge che tali parametri assumono i seguenti valori:

Essendo noti i valori di media e deviazione standard della popolazione, è possibile applicare lo Z-test per verificare entrambe le ipotesi nulle, sia quella relativa al peso, sia quella relativa alla lunghezza alla nascita.

Peso

mu0 <- 3300
sigma <- 500
peso <- na.omit(neonati$Peso)
n <- length(peso)
media_peso <- mean(peso)

Z <- (media_peso - mu0) / (sigma / sqrt(n))

p_value <- 2 * pnorm(-abs(Z))

IC <- c(
  media_peso - qnorm(0.975) * (sigma / sqrt(n)),
  media_peso + qnorm(0.975) * (sigma / sqrt(n))
)

cat(sprintf(
  "Media campionaria: %.2f | Statistica Z: %.4f | p-value: %s | IC 95%%: [%.2f; %.2f]\n",
  media_peso, Z, format.pval(p_value, digits = 10), IC[1], IC[2]
))
## Media campionaria: 3284.08 | Statistica Z: -1.5919 | p-value: 0.1114026811 | IC 95%: [3264.48; 3303.68]

L’output mostra il risultato di un test Z per valutare se la media del peso neonatale differisce significativamente dal valore noto di riferimento di 3300 grammi. Il p-value ottenuto è superiore ai comuni livelli di significatività (es. 0.05), il che indica che non rifiutiamo l’ipotesi nulla e concludiamo che la media del peso non è significativamente diversa da quella della popolazione.

curve(dnorm(x, 0, 1),
      from = -4, to = 4,
      col = "blue", lwd = 2,
      main = "Distribuzione Normale sotto H0",
      xlab = "Z", ylab = "Densità")
abline(v = c(-qnorm(0.975), qnorm(0.975)), col = "red", lty = 2, lwd = 2)
points(Z, 0, col = "darkgreen", pch = 19, cex = 2)
legend("topright",
       legend = c("N(0,1)", "Soglie critiche", "Z osservato"),
       col = c("blue", "red", "darkgreen"),
       lwd = c(2, 2, NA), lty = c(1, 2, NA), pch = c(NA, NA, 19))

Il grafico mostra la distribuzione normale standard sotto l’ipotesi nulla (Z ~ N(0,1)) per il test Z sul peso neonatale. Le linee rosse tratteggiate rappresentano i valori soglia critici a ±1.96, corrispondenti a un livello di significatività del 5% (α = 0.05) per un test bilaterale. Il punto verde indica il valore Z osservato e si trova all’interno dell’intervallo di accettazione.

Questo conferma visivamente quanto evidenziato dall’output numerico:

Lunghezza

mu0 <- 500
sigma <- 20  

lung <- na.omit(neonati$Lunghezza)
n <- length(lung)
media_lung <- mean(lung)


Z_stat <- (media_lung - mu0) / (sigma / sqrt(n))
p_value <- 2 * pnorm(-abs(Z_stat))


IC <- c(
  media_lung - qnorm(0.975) * (sigma / sqrt(n)),
  media_lung + qnorm(0.975) * (sigma / sqrt(n))
)


cat(sprintf(
  "Media campionaria: %.2f | Statistica Z: %.4f | p-value: %s | IC 95%%: [%.2f; %.2f]\n",
  media_lung, Z_stat, format.pval(p_value, digits = 15), IC[1], IC[2]
))
## Media campionaria: 494.69 | Statistica Z: -13.2700 | p-value: < 2.22044604925e-16 | IC 95%: [493.91; 495.48]

Il test Z mostra che la lunghezza neonatale media del campione (494.69) è significativamente diversa da quella della popolazione di riferimento (p-value < 2.22e-16), con un intervallo di confidenza al 95% [493.91; 495.48] che non include la media attesa: la differenza è quindi altamente significativa dal punto di vista statistico.

curve(dnorm(x), from = -15, to = 15, col = "blue", lwd = 2,
      main = "Distribuzione Normale Standard sotto H0 (test Z)",
      xlab = "Valori Z", ylab = "Densità")
abline(v = c(-qnorm(0.975), qnorm(0.975)), col = "red", lty = 2, lwd = 2)
points(Z_stat, 0, col = "darkgreen", pch = 19, cex = 2)

legend("topright",
       legend = c("Distribuzione Normale Standard", 
                  "Soglie critiche ±z(0.975)", 
                  "Z osservato"),
       col = c("blue", "red", "darkgreen"),
       lwd = c(2, 2, NA), lty = c(1, 2, NA), pch = c(NA, NA, 19))

Il grafico mostra come il valore Z osservato per la lunghezza sia molto distante dal centro della distribuzione, indicando una forte significatività statistica. Questo ci porta a rifiutare con sicurezza l’ipotesi nulla. In particolare:

In conclusione, c’è una chiara evidenza di una differenza reale nella lunghezza media della popolazione rispetto all’ipotesi iniziale.

Le misure antropometriche sono significativamente diverse tra i due sessi

Per confrontare le misure antropometriche tra maschi e femmine è stato utilizzato il test t di Student. Poiché l’analisi riguarda tre diverse variabili (lunghezza, peso e circonferenza cranica), è stata creata una funzione che consente di evitare la ripetizione del codice per ciascun confronto.

t_test_confronto <- function(x1, x2, nome_variabile = "Variabile") {
  x1 <- na.omit(x1)
  x2 <- na.omit(x2)
  
  n1 <- length(x1)
  n2 <- length(x2)
  m1 <- mean(x1)
  m2 <- mean(x2)
  s1 <- sd(x1)
  s2 <- sd(x2)
  

  se <- sqrt(s1^2/n1 + s2^2/n2)
  t_stat <- (m1 - m2) / se
  df <- (s1^2/n1 + s2^2/n2)^2 / ((s1^2/n1)^2/(n1-1) + (s2^2/n2)^2/(n2-1))
  p_value <- 2 * pt(-abs(t_stat), df)
  
  IC <- c((m1 - m2) - qt(0.975, df)*se, (m1 - m2) + qt(0.975, df)*se)
  
  cat(sprintf(
    "Confronto %s (Maschi - Femmine) | Diff. medie: %.2f | t: %.4f | p-value: %s | IC 95%%: [%.2f; %.2f]\n",
    nome_variabile, m1 - m2, t_stat, format.pval(p_value, digits = 15), IC[1], IC[2]
  ))
  
  curve(dt(x, df), from = -15, to = 15, col = "blue", lwd = 2,
        main = paste("t-test:", nome_variabile, "(Maschi - Femmine)"),
        xlab = "Valori t", ylab = "Densità")
  abline(v = c(-qt(0.975, df), qt(0.975, df)), col = "red", lty = 2, lwd = 2)
  points(t_stat, 0, col = "darkgreen", pch = 19, cex = 2)
  legend("topright",
         legend = c("Distribuzione t", "Soglie critiche", "t osservato"),
         col = c("blue", "red", "darkgreen"),
         lwd = c(2, 2, NA), lty = c(1, 2, NA), pch = c(NA, NA, 19))
}

t_test_confronto(neonati$Lunghezza[neonati$Sesso == "M"],
                 neonati$Lunghezza[neonati$Sesso == "F"],
                 nome_variabile = "Lunghezza")
## Confronto Lunghezza (Maschi - Femmine) | Diff. medie: 9.90 | t: 9.5820 | p-value: < 2.22044604925e-16 | IC 95%: [7.88; 11.93]

t_test_confronto(neonati$Peso[neonati$Sesso == "M"],
                 neonati$Peso[neonati$Sesso == "F"],
                 nome_variabile = "Peso")
## Confronto Peso (Maschi - Femmine) | Diff. medie: 247.08 | t: 12.1061 | p-value: < 2.22044604925e-16 | IC 95%: [207.06; 287.11]

t_test_confronto(neonati$Cranio[neonati$Sesso == "M"],
                 neonati$Cranio[neonati$Sesso == "F"],
                 nome_variabile = "Cranio")
## Confronto Cranio (Maschi - Femmine) | Diff. medie: 4.82 | t: 7.4102 | p-value: 1.71769469990384e-13 | IC 95%: [3.54; 6.09]

Tutti e tre i confronti mostrano differenze significative tra i sessi, con i maschi che mediamente presentano valori più elevati per lunghezza, peso e circonferenza cranica. Queste evidenze statistiche suggeriscono che il sesso del neonato è un fattore associato in modo sistematico alle sue misure antropometriche alla nascita.

SCATTERPLOT E CORRELAZIONI

panel.cor <- function(x, y, digits=2, prefix="", cex.cor, ...) {
  usr <- par("usr")
  on.exit(par(usr = usr)) 
  par(usr = c(0,1,0,1))
  r <- cor(x, y, use="complete.obs")
  txt <- format(c(r, 0.123456789), digits=digits)[1]
  txt <- paste0(prefix, txt)
  if(missing(cex.cor)) cex.cor <- 0.8 / strwidth(txt)
  text(0.5, 0.5, txt, cex=cex.cor)
}

pairs(neonati[, c("Anni.madre", "N.gravidanze", "Gestazione", "Peso", "Lunghezza", "Cranio")],
      lower.panel=panel.cor, upper.panel=panel.smooth)

Le correlazioni più forti si osservano tra le misure antropometriche (peso, lunghezza, cranio), che risultano strettamente interconnesse. In particolare:

Nel complesso, il pattern emerso suggerisce l’importanza della gestazione come variabile predittiva.

Modello di regressione lineare completo

mod_full <- lm(Peso ~ Anni.madre + N.gravidanze + Gestazione + Fumatrici + Sesso + Tipo.parto + Ospedale, data = neonati)
summary(mod_full)
## 
## Call:
## lm(formula = Peso ~ Anni.madre + N.gravidanze + Gestazione + 
##     Fumatrici + Sesso + Tipo.parto + Ospedale, data = neonati)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1488.2  -270.1   -13.6   262.7  1905.9 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -3306.932    187.373 -17.649  < 2e-16 ***
## Anni.madre        3.742      1.706   2.193  0.02838 *  
## N.gravidanze     18.437      7.010   2.630  0.00859 ** 
## Gestazione      163.461      4.520  36.163  < 2e-16 ***
## Fumatrici      -110.330     41.498  -2.659  0.00790 ** 
## SessoM          164.712     16.699   9.863  < 2e-16 ***
## Tipo.partoNat    15.329     18.213   0.842  0.40007    
## Ospedaleosp2     -1.426     20.273  -0.070  0.94395    
## Ospedaleosp3     23.949     20.366   1.176  0.23974    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 413.4 on 2491 degrees of freedom
## Multiple R-squared:  0.3821, Adjusted R-squared:  0.3801 
## F-statistic: 192.6 on 8 and 2491 DF,  p-value: < 2.2e-16

Il modello lineare completo mostra una relazione statisticamente significativa tra diverse variabili cliniche e il peso neonatale.

In particolare:

Non risultano invece significative le variabili relative al tipo di parto e alla struttura ospedaliera, che non sembrano influenzare il peso in modo rilevante nel campione analizzato.

vif(mod_full)
##                  GVIF Df GVIF^(1/(2*Df))
## Anni.madre   1.183690  1        1.087975
## N.gravidanze 1.178562  1        1.085616
## Gestazione   1.043345  1        1.021443
## Fumatrici    1.004497  1        1.002246
## Sesso        1.019952  1        1.009927
## Tipo.parto   1.001659  1        1.000829
## Ospedale     1.003131  2        1.000782

L’analisi dei VIF conferma l’assenza di collinearità tra le variabili indipendenti, con valori ben al di sotto delle soglie critiche. Questo rafforza l’affidabilità delle stime ottenute.

In sintesi, il modello è solido e mostra evidenza chiara di più fattori clinici significativi associati al peso neonatale.

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

shapiro.test(residuals(mod_full))
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(mod_full)
## W = 0.9969, p-value = 5.722e-05

Il test di Shapiro-Wilk restituisce W = 0.9969 con un p-value = 5.722e-05, indicando che, sebbene i residui siano visivamente quasi normali (W vicino a 1), la normalità è formalmente rifiutata a livello di significatività del 5%. Dunque, i residui non seguono una distribuzione normale in modo statisticamente significativo, anche se la deviazione appare contenuta.

bptest(mod_full)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod_full
## BP = 13.553, df = 8, p-value = 0.09418

Il test di Breusch-Pagan restituisce BP = 13.553 con p-value = 0.09418, indicando che non si rifiuta l’ipotesi nulla di omoschedasticità. Pertanto, non emergono evidenze statisticamente significative di eteroschedasticità dei residui, suggerendo che la varianza degli errori può essere considerata costante.

dwtest(mod_full)
## 
##  Durbin-Watson test
## 
## data:  mod_full
## DW = 1.8939, p-value = 0.003997
## alternative hypothesis: true autocorrelation is greater than 0

Il test di Durbin-Watson restituisce DW = 1.8939 con un p-value = 0.003997: sebbene il valore DW sia vicino a 2 (indicando apparentemente assenza di autocorrelazione), il p-value < 0.05 porta a rifiutare l’ipotesi nulla di indipendenza dei residui. Si conclude quindi che è presente un’autocorrelazione positiva significativa tra i residui.

SELEZIONE MODELLO RIDOTTO

n <- nrow(neonati)
step_mod <- stepAIC(mod_full, direction = "both", k = log(n))
## Start:  AIC=30183.19
## Peso ~ Anni.madre + N.gravidanze + Gestazione + Fumatrici + Sesso + 
##     Tipo.parto + Ospedale
## 
##                Df Sum of Sq       RSS   AIC
## - Ospedale      2    338648 426000786 30170
## - Tipo.parto    1    121043 425783181 30176
## - Anni.madre    1    821976 426484114 30180
## - N.gravidanze  1   1182030 426844167 30182
## - Fumatrici     1   1207859 426869997 30182
## <none>                      425662138 30183
## - Sesso         1  16624132 442286270 30271
## - Gestazione    1 223470325 649132463 31230
## 
## Step:  AIC=30169.53
## Peso ~ Anni.madre + N.gravidanze + Gestazione + Fumatrici + Sesso + 
##     Tipo.parto
## 
##                Df Sum of Sq       RSS   AIC
## - Tipo.parto    1    130235 426131021 30162
## - Anni.madre    1    845501 426846287 30167
## - N.gravidanze  1   1206111 427206897 30169
## - Fumatrici     1   1231187 427231973 30169
## <none>                      426000786 30170
## + Ospedale      2    338648 425662138 30183
## - Sesso         1  16674239 442675025 30258
## - Gestazione    1 223933725 649934511 31218
## 
## Step:  AIC=30162.47
## Peso ~ Anni.madre + N.gravidanze + Gestazione + Fumatrici + Sesso
## 
##                Df Sum of Sq       RSS   AIC
## - Anni.madre    1    846924 426977945 30160
## - N.gravidanze  1   1188774 427319795 30162
## - Fumatrici     1   1215268 427346289 30162
## <none>                      426131021 30162
## + Tipo.parto    1    130235 426000786 30170
## + Ospedale      2    347841 425783181 30176
## - Sesso         1  16667830 442798852 30251
## - Gestazione    1 223815017 649946038 31210
## 
## Step:  AIC=30159.61
## Peso ~ N.gravidanze + Gestazione + Fumatrici + Sesso
## 
##                Df Sum of Sq       RSS   AIC
## - Fumatrici     1   1233672 428211618 30159
## <none>                      426977945 30160
## + Anni.madre    1    846924 426131021 30162
## - N.gravidanze  1   2379729 429357675 30166
## + Tipo.parto    1    131658 426846287 30167
## + Ospedale      2    371728 426606218 30173
## - Sesso         1  16780605 443758551 30248
## - Gestazione    1 223417523 650395468 31204
## 
## Step:  AIC=30159
## Peso ~ N.gravidanze + Gestazione + Sesso
## 
##                Df Sum of Sq       RSS   AIC
## <none>                      428211618 30159
## + Fumatrici     1   1233672 426977945 30160
## + Anni.madre    1    865329 427346289 30162
## - N.gravidanze  1   2216633 430428251 30164
## + Tipo.parto    1    115547 428096071 30166
## + Ospedale      2    395946 427815672 30172
## - Sesso         1  16718785 444930403 30247
## - Gestazione    1 222513567 650725185 31197

La selezione del modello mediante procedura stepwise basata sul criterio BIC ha portato a un modello finale composto da tre variabili: Numero di gravidanze, Settimane di gestazione e Sesso del neonato. Le altre variabili presenti nel modello iniziale (come Fumatrici, Anni della madre, Tipo di parto e Ospedale) sono state progressivamente escluse in quanto non apportavano un miglioramento sufficiente al bilanciamento tra bontà di adattamento e complessità del modello secondo il criterio BIC. Tra le variabili selezionate, la Gestazione si conferma come il principale predittore del peso neonatale.

summary(step_mod)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Sesso, data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1494.15  -272.82   -14.43   267.31  1892.39 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -3136.835    175.410 -17.883  < 2e-16 ***
## N.gravidanze    23.395      6.509   3.595 0.000331 ***
## Gestazione     162.025      4.499  36.014  < 2e-16 ***
## SessoM         165.144     16.729   9.872  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 414.2 on 2496 degrees of freedom
## Multiple R-squared:  0.3784, Adjusted R-squared:  0.3777 
## F-statistic: 506.5 on 3 and 2496 DF,  p-value: < 2.2e-16

Il modello finale stima il peso neonatale in funzione di:

Tutte le variabili sono statisticamente significative (p < 0,001), con Gestazione come principale predittore: ogni settimana in più di gestazione aumenta il peso di circa 162 grammi, mentre ogni gravidanza in più si associa in media a un aumento di circa 23 grammi.

L’R² pari a 37,8% indica che il modello spiega circa il 38% della variabilità del peso neonatale. I residui mostrano una variabilità ragionevole (errore standard residuo ≈ 414 grammi) e una distribuzione bilanciata intorno allo zero.

Il modello risulta statisticamente significativo nel suo complesso (F = 506,5; p < 0,001) e conferma il ruolo centrale della durata della gravidanza nel determinare il peso alla nascita. Il sesso maschile, infine, si associa coerentemente a un peso medio superiore.

Prova di interazioni

mod_inter<- lm(Peso ~ N.gravidanze + Sesso + Gestazione * Fumatrici, data = neonati)
summary(mod_inter)
## 
## Call:
## lm(formula = Peso ~ N.gravidanze + Sesso + Gestazione * Fumatrici, 
##     data = neonati)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1498.69  -273.34   -14.34   264.56  1892.01 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)          -3196.668    177.196 -18.040  < 2e-16 ***
## N.gravidanze            24.367      6.506   3.745 0.000184 ***
## SessoM                 166.750     16.718   9.974  < 2e-16 ***
## Gestazione             163.634      4.544  36.009  < 2e-16 ***
## Fumatrici             1883.300   1140.061   1.652 0.098675 .  
## Gestazione:Fumatrici   -50.808     29.019  -1.751 0.080094 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 413.5 on 2494 degrees of freedom
## Multiple R-squared:  0.381,  Adjusted R-squared:  0.3797 
## F-statistic:   307 on 5 and 2494 DF,  p-value: < 2.2e-16
anova(step_mod, mod_inter)
## Analysis of Variance Table
## 
## Model 1: Peso ~ N.gravidanze + Gestazione + Sesso
## Model 2: Peso ~ N.gravidanze + Sesso + Gestazione * Fumatrici
##   Res.Df       RSS Df Sum of Sq      F   Pr(>F)   
## 1   2496 428211618                                
## 2   2494 426453773  2   1757845 5.1401 0.005919 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Il modello con l’interazione tra Gestazione e Fumatrici migliora significativamente la spiegazione del peso neonatale rispetto al modello senza interazioni (p = 0.0059, test ANOVA).

Nello specifico:

In conclusione, includere l’interazione tra gestazione e fumo materno risulta corretto e utile per cogliere dinamiche più complesse.

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

L’analisi diagnostica dei residui evidenzia:

L’analisi dei residui mostra lievi non-linearità, variabilità non costante e alcuni outlier influenti. Pur essendo il modello significativo, questi aspetti suggeriscono di considerare ulteriori miglioramenti per aumentare la sua robustezza e precisione predittiva.

shapiro.test(residuals(mod_inter))
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(mod_inter)
## W = 0.99683, p-value = 4.488e-05

Il test di Shapiro-Wilk indica una lieve deviazione dalla normalità (p-value molto basso), suggerendo che i residui non seguono perfettamente una distribuzione normale, probabilmente a causa di outlier o code pesanti. Tuttavia, la deviazione non è drammatica.

bptest(mod_inter)
## 
##  studentized Breusch-Pagan test
## 
## data:  mod_inter
## BP = 6.9002, df = 5, p-value = 0.2282

Il test di Breusch-Pagan non rileva evidenze di varianza non costante dei residui (p-value > 0.2), quindi l’ipotesi di omoschedasticità è ragionevole. Ciò significa che la dispersione degli errori è stabile lungo i valori predetti.

dwtest(mod_inter)
## 
##  Durbin-Watson test
## 
## data:  mod_inter
## DW = 1.8957, p-value = 0.004543
## alternative hypothesis: true autocorrelation is greater than 0

Il test di Durbin-Watson evidenzia una autocorrelazione positiva significativa tra i residui (p-value < 0.01), indicando che gli errori non sono indipendenti, il che può influenzare l’affidabilità delle stime e richiede attenzione.

In conclusione, il modello mostra una buona adeguatezza generale, ma presenta alcune criticità: la non normalità lieve dei residui e la presenza di autocorrelazione possono influenzare l’affidabilità delle inferenze. La stabilità della varianza degli errori è invece confermata.

Validazione del modello

train_indices <- sample(seq_len(nrow(neonati)), size = 0.7 * nrow(neonati))
train_data <- neonati[train_indices, ]
test_data <- neonati[-train_indices, ]


mod_train <- lm(Peso ~ Anni.madre + N.gravidanze + Gestazione * Fumatrici + Sesso + Tipo.parto + Ospedale,
                data = train_data)


pred_train <- predict(mod_train, newdata = train_data)
pred_test <- predict(mod_train, newdata = test_data)


MSE <- function(y_obs, y_pred) mean((y_obs - y_pred)^2)
mse_train <- MSE(train_data$Peso, pred_train)
rmse_train <- sqrt(mse_train)
mse_test <- MSE(test_data$Peso, pred_test)
rmse_test <- sqrt(mse_test)

print(paste("MSE su training:", round(mse_train, 2)))
## [1] "MSE su training: 163932.2"
print(paste("RMSE su training:", round(rmse_train, 2)))
## [1] "RMSE su training: 404.89"
print(paste("MSE su test:", round(mse_test, 2)))
## [1] "MSE su test: 185213.13"
print(paste("RMSE su test:", round(rmse_test, 2)))
## [1] "RMSE su test: 430.36"

La validazione del modello è stata effettuata dividendo il dataset in training (70%) e test (30%).

Il modello è stato costruito sui dati di training e poi utilizzato per prevedere il peso neonatale sia nel training che nel test.

In sintesi, il modello mostra una performance stabile su dati nuovi, confermando la sua affidabilità per la previsione del peso neonatale.

Previsione

Supponiamo di applicare il modello finale mod_inter per stimare il peso alla nascita di un neonato in un caso specifico:

new_neonate <- data.frame(
  Anni.madre = 30,          
  N.gravidanze = 3,
  Gestazione = 39,
  Fumatrici = 1,       
  Sesso = factor("M", levels = c("F", "M")),
  Tipo.parto = factor("Nat", levels = c("Nat", "Ces")),
  Ospedale = factor("osp1", levels = c("osp1", "osp2", "osp3"))
)

peso_previsto <- predict(mod_inter, newdata = new_neonate)
print(paste("Peso previsto (grammi):", round(peso_previsto, 1)))
## [1] "Peso previsto (grammi): 3326.7"

La previsione ottenuta indica un peso stimato di circa 3327 grammi. Questo valore rappresenta la stima del modello basata sulle variabili incluse, fornendo un esempio pratico di come il modello possa essere applicato per valutare il peso atteso di un neonato con determinate condizioni materne e cliniche

Effetto combinato tra Gestazione e Fumo

ggplot(neonati, aes(x = Gestazione, y = Peso, color = factor(Fumatrici))) +
  geom_point(alpha = 0.4) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  facet_wrap(~Fumatrici) +
  scale_color_manual(
    name = "Fumatrici",
    values = c("0" = "blue", "1" = "red"),
    labels = c("Non Fumatrici", "Fumatrici")
  ) +
  labs(
    title = "Peso in funzione della Gestazione e Fumo Materno",
    x = "Settimane di Gestazione",
    y = "Peso del neonato (g)"
  ) +
  theme_minimal()

ggplot(neonati, aes(x = Gestazione, y = Peso, color = factor(Fumatrici), group = Fumatrici)) +
  geom_point(alpha = 0.4) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  labs(title = "Interazione: Fumo materno e Settimane di Gestazione",
       x = "Gestazione (settimane)", y = "Peso (g)", color = "Fumatrici") +
  theme_light()

I risultati mostrano che il fumo materno ha un effetto costante e persistente sul peso alla nascita durante tutta la gravidanza. La differenza di peso tra neonati di madri fumatrici e non fumatrici si mantiene relativamente stabile dall’inizio alla fine della gestazione.

Diagnostica residui

ggplot(data = data.frame(Fitted = fitted(mod_inter), Residuals = resid(mod_inter)), 
       aes(x = Fitted, y = Residuals)) +
  geom_point(alpha = 0.5) +
  geom_hline(yintercept = 0, col = "red", linetype = "dashed") +
  labs(title = "Residui vs Valori Predetti", x = "Valori Predetti", y = "Residui") +
  theme_minimal()

Il grafico mostra in modo chiaro che l’assunzione di omoschedasticità non è rispettata. I punti non si distribuiscono in modo uniforme intorno alla linea orizzontale, ma formano un evidente pattern a imbuto: la varianza dei residui aumenta all’aumentare dei valori predetti. Questo indica che il modello commette errori crescenti per i neonati con peso maggiore, segnalando la possibilità di una varianza non costante che dovrebbe essere corretta. Inoltre, si osserva una forte concentrazione di dati nella fascia 3000-3500 grammi, mentre alcuni residui molto distanti, in particolare due sopra i 1500 e uno oltre i 1800, suggeriscono la presenza di outlier potenzialmente influenti.

ggplot(data = data.frame(Residuals = resid(mod_inter)), aes(sample = Residuals)) +
  stat_qq() +
  stat_qq_line(col = "blue") +
  labs(title = "Q-Q Plot dei residui") +
  theme_minimal()

Nel Q-Q plot i residui non seguono perfettamente la linea teorica, soprattutto agli estremi, rivelando code più pesanti di quanto previsto da una distribuzione normale. Questo implica che gli errori non si distribuiscono in modo perfettamente simmetrico e regolare, ma presentano deviazioni significative nelle code. La parte centrale dei punti aderisce bene alla linea, suggerendo che per la maggior parte dei casi la normalità è rispettata.

ggplot(data = data.frame(Residuals = resid(mod_inter)), aes(x = Residuals)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  labs(title = "Distribuzione dei Residui", x = "Residui", y = "Frequenza") +
  theme_minimal()

L’istogramma dei residui conferma quanto osservato negli altri grafici: la distribuzione appare approssimativamente normale, ma presenta irregolarità. Si nota una leggera asimmetria verso destra, con una coda destra più lunga che segnala la presenza di errori positivi particolarmente grandi. Nonostante la maggior parte dei residui sia concentrata intorno a zero, come auspicabile, alcuni valori estremi distorcono la forma ideale.

CONCLUSIONE

L’analisi condotta ha evidenziato come la durata della gestazione, il sesso del neonato e il numero di gravidanze siano i principali determinanti del peso alla nascita nel campione esaminato. Inoltre, l’interazione con la variabile relativa alle madri fumatrici suggerisce un effetto ulteriore sul peso neonatale. Il modello finale, pur spiegando una quota parziale della variabilità complessiva, fornisce indicazioni utili per comprendere le dinamiche cliniche alla base del peso neonatale.