knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE, fig.align = "center")

# Installazione e caricamento pacchetti in un unico blocco per pulizia
required_packages <- c("dplyr", "moments", "ggplot2", "scales", "car", "lmtest", "MASS")
new_packages <- required_packages[!(required_packages %in% installed.packages()[,"Package"])]
if(length(new_packages)) install.packages(new_packages)

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(moments)
library(ggplot2)
library(scales)
library(car)    # VIF
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
library(lmtest) # Diagnostica residui (Breusch-Pagan, Durbin-Watson)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(MASS)   # Box-Cox
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select

1. Introduzione e Preparazione Dati

In questo documento analizziamo il dataset relativo alle nascite. L’obiettivo è esplorare le variabili che influenzano il peso del neonato e costruire un modello predittivo performante, confrontando approcci lineari classici con trasformazioni logaritmiche e polinomiali.

# Caricamento dati
# Assicurati che il file neonati.csv sia nella working directory
setwd("~/Desktop/Università/Master Data Science/Progetto 3 - Statistica inferenziale")
data <- read.csv("neonati.csv", sep=",")

# Rimozione valori mancanti (CRUCIALE per confronto modelli e ANOVA)
data <- na.omit(data)

# Anteprima rapida
head(data)
##   Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio Tipo.parto
## 1         26            0         0         42 3380       490    325        Nat
## 2         21            2         0         39 3150       490    345        Nat
## 3         34            3         0         38 3640       500    375        Nat
## 4         28            1         0         41 3690       515    365        Nat
## 5         20            0         0         38 3700       480    335        Nat
## 6         32            0         0         40 3200       495    340        Nat
##   Ospedale Sesso
## 1     osp3     M
## 2     osp1     F
## 3     osp2     M
## 4     osp2     M
## 5     osp3     F
## 6     osp2     F
# Preprocessing: Conversione in Fattori
# Fondamentale per trattare correttamente le variabili categoriche nelle analisi
data$Tipo.parto <- as.factor(data$Tipo.parto)
data$Ospedale <- as.factor(data$Ospedale)
data$Sesso <- as.factor(data$Sesso)
data$Fumatrici <- as.factor(data$Fumatrici) 

2. Analisi Descrittiva (EDA)

2.1 Statistiche Variabili Numeriche

Calcoliamo media, deviazione standard, coefficiente di variazione (CV) e indici di forma.

stats_summary <- data.frame()

for (var in colnames(data)) {
  vec <- data[[var]]
  
  if (is.numeric(vec)) {
    media_val <- mean(vec, na.rm = TRUE)
    sd_val <- sd(vec, na.rm = TRUE)
    
    temp <- data.frame(
      Variabile = var,
      Media = media_val,
      SD = sd_val,
      CV_Percent = (sd_val / media_val) * 100,
      Skewness = skewness(vec, na.rm = TRUE),
      Kurtosis = kurtosis(vec, na.rm = TRUE)
    )
    stats_summary <- rbind(stats_summary, temp)
  }
}

knitr::kable(stats_summary, digits = 2, caption = "Statistiche Descrittive")
Statistiche Descrittive
Variabile Media SD CV_Percent Skewness Kurtosis
Anni.madre 28.16 5.27 18.72 0.04 3.38
N.gravidanze 0.98 1.28 130.51 2.51 13.99
Gestazione 38.98 1.87 4.79 -2.07 11.26
Peso 3284.08 525.04 15.99 -0.65 5.03
Lunghezza 494.69 26.32 5.32 -1.51 9.49
Cranio 340.03 16.43 4.83 -0.79 5.95

2.2 Distribuzione Variabili Continue

Visualizziamo la forma delle distribuzioni (Istogrammi + Densità).

var_continue <- c("Anni.madre", "Peso", "Lunghezza", "Cranio")

for (var in var_continue) {
  mean_val <- mean(data[[var]], na.rm = TRUE)
  
  p <- ggplot(data, aes_string(x = var)) +
    geom_histogram(aes(y = ..density..), bins = 30, fill = "lightblue", color = "white") +
    geom_density(alpha = 0.2, fill = "blue") +
    geom_vline(aes(xintercept = mean_val), color = "red", linetype = "dashed", size = 1) +
    labs(title = paste("Distribuzione di:", var),
         subtitle = paste("Linea rossa = Media (", round(mean_val, 2), ")"),
         x = var, y = "Densità") +
    theme_minimal()
  
  print(p)
}

2.3 Analisi degli Outliers

Utilizziamo il criterio \(1.5 \times IQR\) per identificare i valori anomali.

df_outliers <- data.frame()

for (var in colnames(data)) {
  colonna_corrente <- data[[var]]
  
  if (is.numeric(colonna_corrente)) {
    # Calcolo soglie
    Q1 <- quantile(colonna_corrente, 0.25, na.rm = TRUE)
    Q3 <- quantile(colonna_corrente, 0.75, na.rm = TRUE)
    IQR_val <- Q3 - Q1
    lower_bound <- Q1 - 1.5 * IQR_val
    upper_bound <- Q3 + 1.5 * IQR_val
    
    # Identificazione indici
    idx_outliers <- which(colonna_corrente < lower_bound | colonna_corrente > upper_bound)
    val_outliers <- colonna_corrente[idx_outliers]
    
    # Salvataggio
    if (length(val_outliers) > 0) {
      temp_df <- data.frame(
        Variabile = var,
        Riga_Indice = idx_outliers,
        Valore = val_outliers
      )
      df_outliers <- rbind(df_outliers, temp_df)
    }
    
    # Plot
    boxplot(colonna_corrente, main = paste("Boxplot Outliers:", var), 
            ylab = var, col = "lightblue", outpch = 19, outcol = "red")
    abline(h = c(lower_bound, upper_bound), col = "red", lty = 2)
  }
}

if (nrow(df_outliers) > 0) {
  print(paste("Totale osservazioni classificate come outlier:", nrow(df_outliers)))
  print(table(df_outliers$Variabile))
}
## [1] "Totale osservazioni classificate come outlier: 502"
## 
##   Anni.madre       Cranio   Gestazione    Lunghezza N.gravidanze         Peso 
##           13           48           67           59          246           69

Nota: Quasi il 20% del campione presenta outlier. Sarà necessario monitorare i residui dei modelli per capire se questi valori influenzano negativamente la regressione. Gli outliers tendono ad essere asimettrici negativi, quindi con frequenze maggiori a valori alti.

2.4 Relazione Variabili Discrete vs Peso

Visualizziamo come il peso varia in base alle categorie qualitative.

vars_discrete <- c("N.gravidanze", "Fumatrici", "Tipo.parto", "Ospedale", "Sesso")

for (var in vars_discrete) {
  if (var %in% colnames(data)) {
    p <- ggplot(data, aes_string(x = paste0("as.factor(", var, ")"), 
                                 y = "Peso", 
                                 fill = paste0("as.factor(", var, ")"))) +
      geom_boxplot(alpha = 0.6, outlier.colour = "red") +
      labs(title = paste("Distribuzione Peso per:", var),
           x = var, y = "Peso (g)", fill = var) +
      theme_minimal() +
      theme(legend.position = "none")
    print(p)
  }
}

3. Analisi di Correlazione

3.1 Matrice di Scatterplot e Correlazioni (Pairs Plot)

panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...) {
    usr <- par("usr"); on.exit(par(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 * abs(r) + 0.5) 
}

numeric_cols <- sapply(data, is.numeric)
data_numeric <- na.omit(data[, numeric_cols])

pairs(data_numeric, 
      lower.panel = panel.cor, 
      upper.panel = panel.smooth, 
      main = "Matrice di Scatterplot e Correlazioni",
      pch = 20, col = alpha("black", 0.4))

3.2 Heatmap delle Correlazioni

cor_matrix <- cor(data_numeric, method = "pearson")
melted_cormat <- as.data.frame(as.table(cor_matrix))
names(melted_cormat) <- c("Var1", "Var2", "Correlazione")

ggplot(melted_cormat, aes(x = Var1, y = Var2, fill = Correlazione)) +
  geom_tile(color = "white") +
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", 
                       midpoint = 0, limit = c(-1,1), name="Pearson\nCorr") +
  geom_text(aes(label = round(Correlazione, 2)), color = "black", size = 3) +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
  coord_fixed() +
  labs(title = "Matrice di Correlazione Completa")

3.3 Focus: Età Madre vs Peso Neonato

var_x <- "Anni.madre"
var_y <- "Peso"
cor_test <- cor.test(data[[var_x]], data[[var_y]], method = "spearman")

print(cor_test)
## 
##  Spearman's rank correlation rho
## 
## data:  data[[var_x]] and data[[var_y]]
## S = 2619756994, p-value = 0.7648
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##          rho 
## -0.005986847
ggplot(data, aes_string(x = var_x, y = var_y)) +
  geom_point(alpha = 0.6, color = "darkblue", size = 2) +
  geom_smooth(method = "loess", color = "red", se = TRUE) +
  labs(title = "Relazione Età Madre vs Peso",
       subtitle = paste("Corr (Spearman):", round(cor_test$estimate, 3), 
                        "| P-value:", format.pval(cor_test$p.value, digits=3))) +
  theme_minimal()

Interpretazione: La correlazione non è statisticamente significativa (p > 0.05), suggerendo che l’età della madre non ha una relazione lineare diretta evidente con il peso del nascituro. Si usa in questo caso spearman dato che i dati sono particolarmente asimettrici.

4. Statistica Inferenziale (Test di Ipotesi)

4.1 T-Test e Chi-Quadro

Eseguiamo i test per verificare le differenze tra i gruppi prima della modellazione.

# 1. T-Test: Peso ~ Fumatrici
print("--- T-Test: Peso ~ Fumatrici ---")
## [1] "--- T-Test: Peso ~ Fumatrici ---"
print(t.test(Peso ~ Fumatrici, data = data, var.equal = FALSE))
## 
##  Welch Two Sample t-test
## 
## data:  Peso by Fumatrici
## t = 1.034, df = 114.1, p-value = 0.3033
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
##  -45.61354 145.22674
## sample estimates:
## mean in group 0 mean in group 1 
##        3286.153        3236.346
# Conclusione: Non rifiutiamo H0. Fumo non significativo univariatamente.

# 2. T-Test: Peso ~ Sesso
print("--- T-Test: Peso ~ Sesso ---")
## [1] "--- T-Test: Peso ~ Sesso ---"
print(t.test(Peso ~ Sesso, data = data, var.equal = FALSE))
## 
##  Welch Two Sample t-test
## 
## data:  Peso by Sesso
## t = -12.106, df = 2490.7, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
##  -287.1051 -207.0615
## sample estimates:
## mean in group F mean in group M 
##        3161.132        3408.215
# Conclusione: Rifiutiamo H0. Sesso significativo.

# 3. Chi-Quadro: Ospedale vs Tipo di Parto
print("--- Chi-Quadro: Ospedale vs Tipo Parto ---")
## [1] "--- Chi-Quadro: Ospedale vs Tipo Parto ---"
print(chisq.test(table(data$Ospedale, data$Tipo.parto)))
## 
##  Pearson's Chi-squared test
## 
## data:  table(data$Ospedale, data$Tipo.parto)
## X-squared = 1.0972, df = 2, p-value = 0.5778
# Conclusione: Non rifiutiamo H0. Indipendenza tra ospedale e tipo parto.

4.2 Focus Specifico: Numero di Gravidanze

Approfondiamo se essere al primo parto (Primipara, 0) o ai successivi (Pluripara, 1+) influenza il peso.

data <- data %>%
  mutate(Gruppo_Gravidanze = as.factor(ifelse(N.gravidanze == 0, "Primipara", "Pluripara")))

t_test_grav <- t.test(Peso ~ Gruppo_Gravidanze, data = data)
print(t_test_grav)
## 
##  Welch Two Sample t-test
## 
## data:  Peso by Gruppo_Gravidanze
## t = 0.43065, df = 2375.8, p-value = 0.6668
## alternative hypothesis: true difference in means between group Pluripara and group Primipara is not equal to 0
## 95 percent confidence interval:
##  -32.30465  50.48640
## sample estimates:
## mean in group Pluripara mean in group Primipara 
##                3288.066                3278.975
ggplot(data, aes(x = Gruppo_Gravidanze, y = Peso, fill = Gruppo_Gravidanze)) +
  geom_boxplot(alpha = 0.6) +
  labs(title = "Peso Neonato: Primipare vs Pluripare",
       subtitle = paste("P-value T-test:", format.pval(t_test_grav$p.value, digits=3))) +
  theme_minimal()

Conclusione: Il P-value > 0.05 indica che, a livello univariato, non c’è differenza significativa di peso medio tra chi è al primo parto e chi ha già partorito.

5. Modellazione (Regressione Lineare)

Procediamo con la costruzione dei modelli, partendo da quello completo e rimuovendo via via le variabili non significative (Stepwise manuale).

5.1 Selezione Variabili (Modelli Lineari Standard)

# Modello 1: Tutte le variabili (Baseline)
mod1 <- lm(Peso ~ ., data = data)

# Modello 2: Rimozione Fumatrici (non significativa)
mod2 <- update(mod1, . ~ . - Fumatrici)

# Modello 3: Reset su data pulita
mod3 <- lm(Peso ~ ., data = data)

# Modello 4: Rimozione Fumatrici e Ospedale
mod4 <- update(mod3, . ~ . - Fumatrici - Ospedale)

# Modello 5: Rimozione Lunghezza (Test feature importance)
mod5 <- update(mod4, . ~ . - Lunghezza)

# Modello 6: Reintroduzione Lunghezza + Interazione (Cranio*Lunghezza)
mod6 <- update(mod5, . ~ . + Lunghezza + Cranio:Lunghezza)

# Modelli successivi: Rimozione variabili meno significative
mod7 <- update(mod6, . ~ . - Lunghezza - Cranio) 
mod8 <- update(mod7, . ~ . - Tipo.parto)
mod9 <- update(mod8, . ~ . - Anni.madre) # Candidato "Simple & Robust"

# Modello 10: Reintroduzione Lunghezza per verifica stabilità
mod10 <- update(mod9, . ~ . + Lunghezza)

# Modello 11: Rimozione N.gravidanze
mod11 <- update(mod10, . ~ . - N.gravidanze)

# Altri Modelli Test
mod5_rev = update(mod5, ~ . - N.gravidanze - Tipo.parto - Anni.madre)

5.2 Modellazione Avanzata (Trasformazioni e GLM)

Esploriamo trasformazioni della variabile target e termini non lineari.

# --- MODELLO 12: Log-Level Regression ---
# Trasformazione log(Peso) per stabilizzare varianza
mod12 <- lm(log(Peso) ~ . - Fumatrici - N.gravidanze - Ospedale + Lunghezza*Cranio, data = data)

# --- MODELLO 13: Log + Gestazione Quadrata ---
# Aggiungiamo I(Gestazione^2) per catturare l'accelerazione della crescita fetale
mod13 <- update(mod12, . ~ . + I(Gestazione^2))

# --- ANALISI BOX-COX ---
# Verifica lambda ottimale
mod_temp <- lm(Peso ~ . - Fumatrici - N.gravidanze - Ospedale + Lunghezza*Cranio + I(Gestazione^2), data = data)
bc <- boxcox(mod_temp, plotit = FALSE, lambda = seq(-2, 2, by = 0.1))
lambda_opt <- bc$x[which.max(bc$y)]
cat("Lambda Ottimale Box-Cox:", round(lambda_opt, 4), "\n")
## Lambda Ottimale Box-Cox: 0.3
# --- MODELLO 14: Box-Cox ---
if(abs(lambda_opt) > 0.1) {
  data$Peso_BoxCox <- (data$Peso^lambda_opt - 1) / lambda_opt
  mod14 <- lm(Peso_BoxCox ~ . - Fumatrici - N.gravidanze - Ospedale + Lunghezza*Cranio + I(Gestazione^2) - Peso, data = data)
}

# --- MODELLO 15: Lineare + Gestazione Quadrata ---
mod15 <- lm(Peso ~ . - Fumatrici - N.gravidanze - Ospedale + Lunghezza*Cranio + I(Gestazione^2), data = data)

# --- NUOVI MODELLI (Log Predittori) ---
# Modello 999: Mod9 ma con log(Gestazione)
mod999 <- update(mod9, . ~ . - Gestazione + log(Gestazione))

# Modello 1000: Mod999 esteso (Log target e Log gestazione)
mod1000 <- lm(log(Peso) ~ . - N.gravidanze - Tipo.parto - Anni.madre - Lunghezza - Fumatrici - Ospedale - Gestazione + log(Gestazione), data=data)

6. Confronto Globale e Diagnostica

6.1 Classifica Prestazioni (Tutti i Modelli)

Confrontiamo tutti i modelli generati in termini di \(R^2\) Adjusted, AIC, BIC e diagnostica dei residui.

# Recupero lista modelli automatici
auto_models <- ls(pattern = "^mod[0-9]+$")
manual_models <- c("mod5_rev", "mod999", "mod1000")
all_models_names <- unique(c(auto_models, manual_models))

global_results <- data.frame()

for (m_name in all_models_names) {
  if(exists(m_name)) {
    curr_mod <- get(m_name)
    if(inherits(curr_mod, "lm")) {
      summ <- summary(curr_mod)
      
      # Test Residui (su campione se N > 5000)
      res <- resid(curr_mod)
      if(length(res) > 5000) { set.seed(123); res <- sample(res, 5000) }
      
      # P-Values Test Diagnostici (con gestione errori)
      shapiro_p <- tryCatch(shapiro.test(res)$p.value, error=function(e) NA)
      bp_val <- tryCatch(bptest(curr_mod)$p.value, error=function(e) NA)
      dw_val <- tryCatch(dwtest(curr_mod)$p.value, error=function(e) NA)
      
      # Identifica Target
      target_var <- as.character(formula(curr_mod)[[2]])
      if(length(target_var) > 1) target_var <- paste(target_var, collapse=" ") 
      
      temp <- data.frame(
        Modello = m_name, Target = target_var,
        Adj_R2 = summ$adj.r.squared,
        AIC = AIC(curr_mod), BIC = BIC(curr_mod),
        F_Stat = summ$fstatistic[1],
        Shapiro_P = shapiro_p, BP_P = bp_val, DW_P = dw_val
      )
      global_results <- rbind(global_results, temp)
    }
  }
}

# Ordinamento e Formattazione
if(nrow(global_results) > 0) {
  global_results <- global_results[order(global_results$Adj_R2, decreasing = TRUE), ]
  
  global_results_display <- global_results
  fmt_p <- function(x) format.pval(x, digits = 3, eps = 0.001, na.form = "-")
  
  global_results_display$Shapiro_P <- fmt_p(global_results$Shapiro_P)
  global_results_display$BP_P <- fmt_p(global_results$BP_P)
  global_results_display$DW_P <- fmt_p(global_results$DW_P)
  
  print(knitr::kable(global_results_display, digits = 4, row.names = FALSE, 
                     caption = "Performance Globali Modelli"))
}
## 
## 
## Table: Performance Globali Modelli
## 
## |Modello  |Target      | Adj_R2|        AIC|        BIC|      F_Stat|Shapiro_P |BP_P   |DW_P   |
## |:--------|:-----------|------:|----------:|----------:|-----------:|:---------|:------|:------|
## |mod1000  |log Peso    | 0.9959| -15152.141| -15111.373| 122793.1819|<0.001    |<0.001 |0.6224 |
## |mod15    |Peso        | 0.9957|  24782.409|  24852.298|  58328.7523|<0.001    |<0.001 |<0.001 |
## |mod13    |log Peso    | 0.7915|  -5297.276|  -5233.212|   1054.9819|<0.001    |<0.001 |0.0674 |
## |mod12    |log Peso    | 0.7891|  -5269.775|  -5211.535|   1169.7498|<0.001    |<0.001 |0.0600 |
## |mod14    |Peso_BoxCox | 0.7711|   6809.709|   6873.773|    936.1481|<0.001    |<0.001 |0.0830 |
## |mod6     |Peso        | 0.7293|  35156.925|  35220.990|    749.1705|<0.001    |<0.001 |0.1128 |
## |mod10    |Peso        | 0.7287|  35159.623|  35206.216|   1119.7590|<0.001    |<0.001 |0.1224 |
## |mod11    |Peso        | 0.7285|  35160.443|  35201.212|   1342.1720|<0.001    |<0.001 |0.1274 |
## |mod1     |Peso        | 0.7277|  35173.678|  35249.390|    608.1984|<0.001    |<0.001 |0.1170 |
## |mod3     |Peso        | 0.7277|  35173.678|  35249.390|    608.1984|<0.001    |<0.001 |0.1170 |
## |mod2     |Peso        | 0.7277|  35172.931|  35242.819|    668.8271|<0.001    |<0.001 |0.1126 |
## |mod4     |Peso        | 0.7269|  35178.137|  35236.377|    832.4856|<0.001    |<0.001 |0.1142 |
## |mod7     |Peso        | 0.7255|  35190.295|  35242.712|    944.4085|<0.001    |0.295  |0.1080 |
## |mod9     |Peso        | 0.7252|  35191.065|  35231.834|   1319.7599|<0.001    |0.499  |0.1164 |
## |mod8     |Peso        | 0.7251|  35192.670|  35239.262|   1099.5984|<0.001    |0.218  |0.1119 |
## |mod999   |Peso        | 0.7251|  35191.793|  35232.561|   1319.2310|<0.001    |0.467  |0.1200 |
## |mod5_rev |Peso        | 0.5992|  36133.564|  36168.508|    934.8531|<0.001    |0.128  |0.0234 |
## |mod5     |Peso        | 0.5988|  36138.572|  36190.988|    533.9125|<0.001    |0.144  |0.0215 |

6.2 Analisi VIF (Multicollinearità)

vif_data_list <- list()
for (m_name in sort(all_models_names)) {
  if (exists(m_name)) {
    model_obj <- get(m_name)
    if (inherits(model_obj, "lm")) {
      tryCatch({
        vif_res <- vif(model_obj)
        vals <- if (is.matrix(vif_res)) vif_res[, 1] else vif_res
        temp_list <- as.list(vals)
        temp_list$Modello <- m_name
        vif_data_list[[m_name]] <- temp_list
      }, error = function(e) {})
    }
  }
}

if(length(vif_data_list) > 0) {
  vif_table <- bind_rows(vif_data_list) %>% dplyr::select(Modello, everything())
  vif_table <- vif_table %>% mutate(across(everything(), as.character))
  vif_table[is.na(vif_table)] <- "-"
  print(knitr::kable(vif_table, caption = "Livelli di VIF per Variabile"))
}
## 
## 
## Table: Livelli di VIF per Variabile
## 
## |Modello  |Anni.madre       |N.gravidanze     |Fumatrici        |Gestazione       |Lunghezza        |Cranio           |Tipo.parto       |Ospedale         |Sesso            |Gruppo_Gravidanze |Lunghezza:Cranio |Peso_BoxCox      |log(Gestazione)  |I(Gestazione^2)  |Cranio:Lunghezza |
## |:--------|:----------------|:----------------|:----------------|:----------------|:----------------|:----------------|:----------------|:----------------|:----------------|:-----------------|:----------------|:----------------|:----------------|:----------------|:----------------|
## |mod1     |1.1968201538097  |1.95582453346558 |1.00933686150721 |1.70522390768659 |2.0857584335596  |1.63906792154197 |1.0045793702441  |1.00485881581363 |1.04070540206104 |1.88667406791593  |-                |-                |-                |-                |-                |
## |mod10    |-                |1.85340935779114 |-                |1.66084433899482 |5.82461147434374 |-                |-                |-                |1.04107405815535 |1.86406185487713  |5.57242325807231 |-                |-                |-                |-                |
## |mod1000  |-                |-                |-                |-                |-                |2.06891280773069 |-                |-                |1.0539563477396  |1.02848646951495  |-                |2.82599083806204 |1.75839682559755 |-                |-                |
## |mod11    |-                |-                |-                |1.6603678017212  |5.81472521896731 |-                |-                |-                |1.04018284153286 |1.02850740974693  |5.56680403535622 |-                |-                |-                |-                |
## |mod12    |1.13415730702627 |-                |-                |1.86792257450727 |112.732196800078 |92.29337395777   |1.00426397570473 |-                |1.0474708556533  |1.14234398497377  |314.885580676347 |-                |-                |-                |-                |
## |mod13    |1.13464296664542 |-                |-                |519.447570346048 |201.328091704502 |162.919910630903 |1.00426588599791 |-                |1.04912321478107 |1.14489876958434  |551.449429174834 |-                |-                |493.321640208192 |-                |
## |mod14    |1.13464296664547 |-                |-                |519.447570345897 |201.328091704475 |162.919910630886 |1.00426588599791 |-                |1.04912321478106 |1.14489876958428  |551.449429174748 |-                |-                |493.321640208045 |-                |
## |mod15    |1.13495123979753 |-                |-                |523.51444886488  |203.826819243249 |164.211817583939 |1.00629739472524 |-                |1.06750480909462 |1.14714466424463  |552.248192952987 |4.38366767832181 |-                |496.116636034339 |-                |
## |mod2     |1.19668596797496 |1.95555320019302 |-                |1.69823984366408 |2.08192212730182 |1.6388135237447  |1.00417970761843 |1.00443359439492 |1.04047231364652 |1.88303793549059  |-                |-                |-                |-                |-                |
## |mod3     |1.1968201538097  |1.95582453346558 |1.00933686150721 |1.70522390768659 |2.0857584335596  |1.63906792154197 |1.0045793702441  |1.00485881581363 |1.04070540206104 |1.88667406791593  |-                |-                |-                |-                |-                |
## |mod4     |1.19604481566846 |1.95455392409214 |-                |1.69693305264703 |2.08004067893252 |1.63852253342956 |1.00372757631702 |-                |1.04019433488858 |1.88165140158832  |-                |-                |-                |-                |-                |
## |mod5     |1.19604481555786 |1.95195939804381 |-                |1.32924622676014 |-                |1.30547395790098 |1.00114490896784 |-                |1.02870213071338 |1.88164980401082  |-                |-                |-                |-                |-                |
## |mod5_rev |-                |-                |-                |1.30982216532279 |-                |1.30188225663671 |-                |-                |1.02789997739555 |1.02961563638688  |-                |-                |-                |-                |-                |
## |mod6     |1.19607778768903 |1.95544419836685 |-                |1.86817469757152 |112.808960046059 |92.3256269268869 |1.00434770517865 |-                |1.04811608407097 |1.88827610763836  |-                |-                |-                |-                |315.029007024637 |
## |mod7     |1.19529418055755 |1.95241393285817 |-                |1.59141588235532 |-                |-                |1.00120061848155 |-                |1.04005775452098 |1.87732965209732  |-                |-                |-                |-                |1.58535417797033 |
## |mod8     |1.19527476361522 |1.9523193302883  |-                |1.59136863677715 |-                |-                |-                |-                |1.04005775248542 |1.87690167739332  |-                |-                |-                |-                |1.58503406904003 |
## |mod9     |-                |1.85026352080116 |-                |1.57326334943691 |-                |-                |-                |-                |1.03998615519062 |1.86167865038122  |-                |-                |-                |-                |1.58220975631089 |
## |mod999   |-                |1.85078114373214 |-                |-                |-                |-                |-                |-                |1.03967241387812 |1.85903333522014  |-                |-                |1.59379288422143 |-                |1.6062966801985  |

7. Approfondimenti e Conclusioni Finali

Dopo aver analizzato vari modelli, il Modello 9 e il Modello 13 emergono come i più interessanti.

7.1 Confronto Modello 9 vs Modello 1000

Verifichiamo se la trasformazione logaritmica della gestazione (mod1000) è preferibile alla lineare (mod9).

if(exists("mod9") && exists("mod1000")) {
  # Confronto Metriche
  comp_df <- data.frame(
    Metric = c("RSS (Devianza)", "AIC", "Adj. R2"),
    Mod9_Lineare = c(deviance(mod9), AIC(mod9), summary(mod9)$adj.r.squared),
    Mod1000_Log = c(deviance(mod1000), AIC(mod1000), summary(mod1000)$adj.r.squared)
  )
  print(knitr::kable(comp_df, digits = 4, caption = "Confronto Mod9 vs Mod1000"))
  
  # Logica di Decisione
  diff_aic <- AIC(mod1000) - AIC(mod9)
  if (diff_aic > 2) {
    print("Vince MOD9 (AIC più basso). La relazione lineare fitta meglio i dati e ha più senso biologico.")
  } else {
    print("I modelli sono simili, si preferisce Mod9 per semplicità interpretativa.")
  }
  
  # Confronto Grafico Residui
  plot(density(resid(mod9)), col="blue", lwd=2, main="Confronto Residui: Mod9 vs Mod1000")
  lines(density(resid(mod1000)), col="green", lwd=2, lty=2)
  legend("topright", legend=c("Mod9 (Lineare)", "Mod1000 (Log)"), col=c("blue", "green"), lty=c(1, 2))
}
## 
## 
## Table: Confronto Mod9 vs Mod1000
## 
## |Metric         | Mod9_Lineare| Mod1000_Log|
## |:--------------|------------:|-----------:|
## |RSS (Devianza) | 1.889504e+08|      0.3395|
## |AIC            | 3.519107e+04| -15152.1411|
## |Adj. R2        | 7.252000e-01|      0.9959|
## [1] "I modelli sono simili, si preferisce Mod9 per semplicità interpretativa."

7.2 Inferenza Finale (Modello 9)

Il modello finale scelto è il Modello 9, che bilancia accuratezza e interpretabilità. Ecco i risultati inferenziali definitivi.

if(exists("mod9")) {
  summary_mod9 <- summary(mod9)
  print(summary_mod9$coefficients)
  
  # Intervalli di Confidenza
  conf_intervals <- confint(mod9, level = 0.95)
  
  # Forest Plot
  coef_data <- as.data.frame(summary_mod9$coefficients)
  coef_data$Term <- rownames(coef_data)
  coef_data$CI_Low <- conf_intervals[,1]
  coef_data$CI_High <- conf_intervals[,2]
  colnames(coef_data)[1] <- "Estimate"
  coef_data_plot <- coef_data[coef_data$Term != "(Intercept)", ]
  
  ggplot(coef_data_plot, aes(x = Term, y = Estimate)) +
    geom_point(color = "blue", size = 3) +
    geom_errorbar(aes(ymin = CI_Low, ymax = CI_High), width = 0.2, color = "darkblue") +
    geom_hline(yintercept = 0, color = "red", linetype = "dashed") +
    coord_flip() +
    labs(title = "Intervalli di Confidenza (Modello 9)",
         subtitle = "Variabili significative: intervallo non tocca lo zero",
         y = "Stima Coefficiente", x = "Variabile") +
    theme_minimal()
}
##                                 Estimate   Std. Error     t value      Pr(>|t|)
## (Intercept)                -2.781147e+03 1.167771e+02 -23.8158625 3.913020e-113
## N.gravidanze                8.367012e+00 5.848578e+00   1.4306061  1.526684e-01
## Gestazione                  4.146580e+01 3.695879e+00  11.2194682  1.559309e-28
## SessoM                      7.677906e+01 1.122805e+01   6.8381461  1.005353e-11
## Gruppo_GravidanzePrimipara -8.314177e+00 1.513768e+01  -0.5492373  5.828918e-01
## Cranio:Lunghezza            2.615358e-02 4.667644e-04  56.0316500  0.000000e+00

8. Conclusioni Finali

L’analisi condotta ha permesso di identificare i principali determinanti del peso alla nascita attraverso un processo iterativo di selezione delle variabili e confronto tra diversi modelli di regressione.

1. Selezione del Modello Migliore: Dopo aver testato modelli lineari semplici, trasformazioni logaritmiche e polinomiali, il Modello 9 è stato selezionato come il migliore compromesso.

Sebbene modelli più complessi (come quelli con trasformazione logaritmica o termini quadratici) offrissero un leggero incremento dell’R-quadro o un AIC inferiore, la loro complessità aggiuntiva e la difficoltà di interpretazione non giustificavano il guadagno marginale.

Il Modello 9 spiega circa il 72.5% della varianza del peso (Adj R2 ~ 0.725) utilizzando solo variabili lineari e un’interazione significativa.

2. Variabili Significative: Le analisi inferenziali confermano che il peso del neonato è influenzato positivamente e significativamente da:

Dimensioni Corporee: Lunghezza e Cranio (e la loro interazione).

Età Gestazionale: Ogni settimana in più aumenta il peso atteso, sembra seguire una curva non lineare e un aumento esponenziale tendendo verso destra, quindi avvicinandoci al terzo quartile.

Sesso: I maschi tendono a pesare di più delle femmine a parità di altre condizioni.

Numero di Gravidanze: Un fattore emerso solo nell’analisi multivariata.

3. Il Paradosso delle Gravidanze (Effetto di Mascheramento): Un risultato chiave di questo studio è la discrepanza tra l’analisi univariata (T-Test) e quella multivariata riguardo al numero di gravidanze.

Mentre il T-Test non mostrava differenze significative tra primipare e pluripare, il modello di regressione ha rivelato che, a parità di gestazione e dimensioni fisiche, aver avuto gravidanze precedenti contribuisce positivamente al peso. Questo suggerisce che l’effetto biologico dell’esperienza uterina era “mascherato” da altre variabili di confusione nell’analisi semplice.

4. Validità del Modello: L’analisi dei residui ha mostrato una distribuzione approssimativamente normale, con una leggera deviazione sulle code dovuta alla presenza di outlier (circa il 20% del dataset). Tuttavia, i test diagnostici confermano l’assenza di eteroschedasticità grave e di autocorrelazione, rendendo il modello robusto per scopi inferenziali e predittivi.