data <- read.csv("neonati.csv", stringsAsFactors = FALSE)
variables <- data.frame(
name = c("Anni.madre",
"N.gravidanze",
"Fumatrici",
"Gestazione",
"Peso",
"Lunghezza",
"Cranio",
"Tipo.parto",
"Ospedale",
"Sesso"),
type = c("Quantitativa Continua (Scala di rapporti)",
"Quantitativa Discreta (conteggio)",
"Qualitativa Nominale Dicotomica (codificata 0/1)",
"Quantitativa Continua (Scala di rapporti)",
"Quantitativa Continua (Scala di rapporti)",
"Quantitativa Continua (Scala di rapporti)",
"Quantitativa Continua (Scala di rapporti)",
"Qualitativa Nominale Dicotomica",
"Qualitativa Nominale",
"Qualitativa Nominale Dicotomica"),
description = c("Età della madre in anni",
"Numero di gravidanze precedenti della madre",
"Stato di fumatrice (0 = non fumatrice, 1 = fumatrice)",
"Durata della gravidanza in settimane di gestazione",
"Peso del neonato alla nascita (in grammi) — VARIABILE TARGET",
"Lunghezza del neonato (in mm)",
"Diametro del cranio del neonato (in mm)",
"Modalità del parto (Nat = naturale, Ces = cesareo)",
"Ospedale di nascita (osp1, osp2, osp3)",
"Sesso del neonato (M = maschio, F = femmina)")
)
knitr::kable(variables, caption = "Descrizione delle variabili del dataset")
| name | type | description |
|---|---|---|
| Anni.madre | Quantitativa Continua (Scala di rapporti) | Età della madre in anni |
| N.gravidanze | Quantitativa Discreta (conteggio) | Numero di gravidanze precedenti della madre |
| Fumatrici | Qualitativa Nominale Dicotomica (codificata 0/1) | Stato di fumatrice (0 = non fumatrice, 1 = fumatrice) |
| Gestazione | Quantitativa Continua (Scala di rapporti) | Durata della gravidanza in settimane di gestazione |
| Peso | Quantitativa Continua (Scala di rapporti) | Peso del neonato alla nascita (in grammi) — VARIABILE TARGET |
| Lunghezza | Quantitativa Continua (Scala di rapporti) | Lunghezza del neonato (in mm) |
| Cranio | Quantitativa Continua (Scala di rapporti) | Diametro del cranio del neonato (in mm) |
| Tipo.parto | Qualitativa Nominale Dicotomica | Modalità del parto (Nat = naturale, Ces = cesareo) |
| Ospedale | Qualitativa Nominale | Ospedale di nascita (osp1, osp2, osp3) |
| Sesso | Qualitativa Nominale Dicotomica | Sesso del neonato (M = maschio, F = femmina) |
dim(data) # dimensioni (righe x colonne)
## [1] 2500 10
str(data) # struttura variabili e tipi
## '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" ...
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
colSums(is.na(data)) # conteggio NA per colonna
## Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza
## 0 0 0 0 0 0
## Cranio Tipo.parto Ospedale Sesso
## 0 0 0 0
sum(duplicated(data)) # righe duplicate
## [1] 0
summary(data)
## Anni.madre N.gravidanze Fumatrici Gestazione
## Min. : 0.00 Min. : 0.0000 Min. :0.0000 Min. :25.00
## 1st Qu.:25.00 1st Qu.: 0.0000 1st Qu.:0.0000 1st Qu.:38.00
## Median :28.00 Median : 1.0000 Median :0.0000 Median :39.00
## Mean :28.16 Mean : 0.9812 Mean :0.0416 Mean :38.98
## 3rd Qu.:32.00 3rd Qu.: 1.0000 3rd Qu.:0.0000 3rd Qu.:40.00
## Max. :46.00 Max. :12.0000 Max. :1.0000 Max. :43.00
## Peso Lunghezza Cranio Tipo.parto
## Min. : 830 Min. :310.0 Min. :235 Length:2500
## 1st Qu.:2990 1st Qu.:480.0 1st Qu.:330 Class :character
## Median :3300 Median :500.0 Median :340 Mode :character
## Mean :3284 Mean :494.7 Mean :340
## 3rd Qu.:3620 3rd Qu.:510.0 3rd Qu.:350
## Max. :4930 Max. :565.0 Max. :390
## Ospedale Sesso
## Length:2500 Length:2500
## Class :character Class :character
## Mode :character Mode :character
##
##
##
Commenti:
data <- data[data$Anni.madre > 0, ]
nrow(data)
## [1] 2499
data$Tipo.parto <- factor(data$Tipo.parto) # livelli: Ces, Nat (ref = Ces)
data$Ospedale <- factor(data$Ospedale) # livelli: osp1, osp2, osp3 (ref = osp1)
data$Sesso <- factor(data$Sesso) # livelli: F, M (ref = F)
data$Fumatrici <- factor(data$Fumatrici, labels = c("NO","SI"))
str(data)
## 'data.frame': 2499 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 : Factor w/ 2 levels "NO","SI": 1 1 1 1 1 1 1 1 1 1 ...
## $ 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 : Factor w/ 2 levels "Ces","Nat": 2 2 2 2 2 2 2 2 1 1 ...
## $ Ospedale : Factor w/ 3 levels "osp1","osp2",..: 3 1 2 2 3 2 3 1 2 2 ...
## $ Sesso : Factor w/ 2 levels "F","M": 2 1 2 2 1 1 1 2 1 1 ...
# skewness (asimmetria) e kurtosis (curtosi)
# Formula manuale in R base (alternativa senza pacchetto):
# asimmetria = mean((x - mean(x))^3) / sd(x)^3
# curtosi = mean((x - mean(x))^4) / sd(x)^4 # (3 = normale)
sapply(data[c("Peso","Lunghezza","Cranio","Gestazione")],
function(x) c(asimmetria = skewness(x), curtosi = kurtosis(x)))
## Peso Lunghezza Cranio Gestazione
## asimmetria -0.6474534 -1.514637 -0.7857134 -2.064888
## curtosi 5.0306817 9.484052 5.9463144 11.253613
# Istogramma del Peso
ggplot(data, aes(x = Peso)) +
geom_histogram(bins = 40, fill = "#4C72B0", colour = "white") +
labs(title = "Distribuzione del Peso alla nascita", x = "Peso (g)", y = "Frequenza")
# Boxplot del Peso (per leggere gli outlier)
ggplot(data, aes(y = Peso)) +
geom_boxplot(fill = "#4C72B0") +
labs(title = "Boxplot del Peso", y = "Peso (g)")
Commenti:
# Frequenze
sapply(data[c("Fumatrici","Tipo.parto","Ospedale","Sesso")], table)
## $Fumatrici
##
## NO SI
## 2395 104
##
## $Tipo.parto
##
## Ces Nat
## 728 1771
##
## $Ospedale
##
## osp1 osp2 osp3
## 816 849 834
##
## $Sesso
##
## F M
## 1256 1243
# Barplot dei Tipi di Parto
ggplot(data, aes(x = Tipo.parto, fill = Tipo.parto)) +
geom_bar() + labs(title = "Tipo di parto", x = "", y = "Conteggio")
Commenti:
num_vars <- c("Anni.madre","N.gravidanze","Gestazione","Peso","Lunghezza","Cranio")
round(cor(data[num_vars]), 3)
## Anni.madre N.gravidanze Gestazione Peso Lunghezza Cranio
## Anni.madre 1.000 0.381 -0.136 -0.024 -0.064 0.015
## N.gravidanze 0.381 1.000 -0.102 0.002 -0.060 0.039
## Gestazione -0.136 -0.102 1.000 0.592 0.619 0.461
## Peso -0.024 0.002 0.592 1.000 0.796 0.705
## Lunghezza -0.064 -0.060 0.619 0.796 1.000 0.603
## Cranio 0.015 0.039 0.461 0.705 0.603 1.000
# Peso vs Lunghezza
ggplot(data, aes(Lunghezza, Peso)) +
geom_point(alpha = .3, colour = "#4C72B0") +
geom_smooth(method = "lm", colour = "red") +
labs(title = "Peso vs Lunghezza (r = 0.80)")
# Peso vs Gestazione
ggplot(data, aes(Gestazione, Peso)) +
geom_point(alpha = .3, colour = "#55A868") +
geom_smooth(method = "lm", colour = "red") +
labs(title = "Peso vs Gestazione (r = 0.59)")
Commenti:
# Tabella di Contingenza + Test Chi-Quadro di Indipendenza
tab_op <- table(data$Ospedale, data$Tipo.parto)
tab_op
##
## Ces Nat
## osp1 242 574
## osp2 254 595
## osp3 232 602
prop.table(tab_op, margin = 1) # proporzioni di parto per ospedale
##
## Ces Nat
## osp1 0.2965686 0.7034314
## osp2 0.2991755 0.7008245
## osp3 0.2781775 0.7218225
chisq.test(tab_op)
##
## Pearson's Chi-squared test
##
## data: tab_op
## X-squared = 1.0604, df = 2, p-value = 0.5885
Commenti:
# Valori di Riferimento della Popolazione
mu_peso <- 3300 # g
mu_lunghezza <- 500 # mm
# t-test a un campione (H0: media campionaria = media popolazione)
t.test(data$Peso, mu = mu_peso)
##
## One Sample t-test
##
## data: data$Peso
## t = -1.5069, df = 2498, p-value = 0.132
## alternative hypothesis: true mean is not equal to 3300
## 95 percent confidence interval:
## 3263.572 3304.769
## sample estimates:
## mean of x
## 3284.17
t.test(data$Lunghezza, mu = mu_lunghezza)
##
## One Sample t-test
##
## data: data$Lunghezza
## t = -10.077, df = 2498, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 500
## 95 percent confidence interval:
## 493.6613 495.7265
## sample estimates:
## mean of x
## 494.6939
Commenti:
# t-test a due campioni (Welch) M vs F su Peso, Lunghezza, Cranio
t.test(Peso ~ Sesso, data = data)
##
## Welch Two Sample t-test
##
## data: Peso by Sesso
## t = -12.116, df = 2490, 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.3966 -207.3302
## sample estimates:
## mean in group F mean in group M
## 3161.132 3408.496
t.test(Lunghezza ~ Sesso, data = data)
##
## Welch Two Sample t-test
##
## data: Lunghezza by Sesso
## t = -9.5864, df = 2459, 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:
## -11.937899 -7.883398
## sample estimates:
## mean in group F mean in group M
## 489.7643 499.6750
t.test(Cranio ~ Sesso, data = data)
##
## Welch Two Sample t-test
##
## data: Cranio by Sesso
## t = -7.4237, df = 2490.6, p-value = 1.555e-13
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
## -6.100260 -3.550953
## sample estimates:
## mean in group F mean in group M
## 337.6330 342.4586
Commenti:
# modello con TUTTE le variabili candidate
mod_full <- lm(Peso ~ Anni.madre + N.gravidanze + Fumatrici + Gestazione +
Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso,
data = data)
summary(mod_full)
##
## Call:
## lm(formula = Peso ~ Anni.madre + N.gravidanze + Fumatrici + Gestazione +
## Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1123.78 -181.66 -14.68 160.85 2612.15
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6736.2566 141.4463 -47.624 < 2e-16 ***
## Anni.madre 0.8428 1.1394 0.740 0.4596
## N.gravidanze 11.3151 4.6632 2.426 0.0153 *
## FumatriciSI -30.2121 27.5435 -1.097 0.2728
## Gestazione 32.5558 3.8195 8.524 < 2e-16 ***
## Lunghezza 10.2945 0.3007 34.231 < 2e-16 ***
## Cranio 10.4695 0.4261 24.570 < 2e-16 ***
## Tipo.partoNat 29.5837 12.0873 2.447 0.0145 *
## Ospedaleosp2 -11.2033 13.4402 -0.834 0.4046
## Ospedaleosp3 28.2392 13.5030 2.091 0.0366 *
## SessoM 77.6415 11.1824 6.943 4.87e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274 on 2488 degrees of freedom
## Multiple R-squared: 0.7289, Adjusted R-squared: 0.7278
## F-statistic: 668.9 on 10 and 2488 DF, p-value: < 2.2e-16
Commenti:
# Selezione stepwise bidirezionale basata su AIC
mod_step <- step(mod_full, direction = "both", trace = FALSE)
summary(mod_step)
##
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio +
## Tipo.parto + Ospedale + Sesso, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1113.13 -181.41 -16.58 160.98 2620.17
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6706.7806 135.9719 -49.325 < 2e-16 ***
## N.gravidanze 12.3308 4.3337 2.845 0.00447 **
## Gestazione 31.9951 3.7902 8.441 < 2e-16 ***
## Lunghezza 10.3086 0.3004 34.311 < 2e-16 ***
## Cranio 10.4896 0.4256 24.649 < 2e-16 ***
## Tipo.partoNat 29.3491 12.0845 2.429 0.01523 *
## Ospedaleosp2 -11.0236 13.4384 -0.820 0.41212
## Ospedaleosp3 28.7952 13.4947 2.134 0.03295 *
## SessoM 77.5562 11.1800 6.937 5.08e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274 on 2490 degrees of freedom
## Multiple R-squared: 0.7287, Adjusted R-squared: 0.7278
## F-statistic: 836 on 8 and 2490 DF, p-value: < 2.2e-16
AIC(mod_full, mod_step)
## df AIC
## mod_full 12 35158.74
## mod_step 10 35156.50
BIC(mod_full, mod_step)
## df BIC
## mod_full 12 35228.62
## mod_step 10 35214.74
Commenti:
mod_final <- lm(Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso,
data = data)
summary(mod_final)
##
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio +
## Sesso, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1149.48 -180.96 -15.52 163.62 2639.77
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6680.5886 135.7556 -49.210 < 2e-16 ***
## N.gravidanze 12.4521 4.3409 2.869 0.00416 **
## Gestazione 32.3363 3.7986 8.513 < 2e-16 ***
## Lunghezza 10.2484 0.3007 34.084 < 2e-16 ***
## Cranio 10.5383 0.4264 24.717 < 2e-16 ***
## SessoM 78.0811 11.2068 6.967 4.12e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274.7 on 2493 degrees of freedom
## Multiple R-squared: 0.727, Adjusted R-squared: 0.7264
## F-statistic: 1328 on 5 and 2493 DF, p-value: < 2.2e-16
BIC(mod_full, mod_final)
## df BIC
## mod_full 12 35228.62
## mod_final 7 35206.90
Commenti:
r2 <- summary(mod_final)$r.squared
rmse <- sqrt(mean(residuals(mod_final)^2))
c(R2 = round(r2, 4), RMSE_g = round(rmse, 1))
## R2 RMSE_g
## 0.727 274.300
Commenti:
par(mfrow = c(2, 2))
plot(mod_final)
par(mfrow = c(1, 1))
Commenti:
# Distanza di Cook per Individuare Osservazioni Influenti
cook <- cooks.distance(mod_final)
# Soglia comunemente utilizzata
threshold <- 4 / nrow(data)
# Numero di osservazioni che superano la soglia
n_influential <- sum(cook > threshold)
# Indice dell'osservazione con la Cook's Distance più elevata
idx_max <- which.max(cook)
# Valore massimo della Cook's Distance
cook_max <- max(cook)
# Stampo un riepilogo
cat(
"Soglia Cook's Distance:", round(threshold, 4),
"\nNumero di osservazioni sopra soglia:", n_influential,
"\nOsservazione più influente:", idx_max,
"\nCook's Distance massima:", round(cook_max, 4),
"\n"
)
## Soglia Cook's Distance: 0.0016
## Numero di osservazioni sopra soglia: 124
## Osservazione più influente: 1550
## Cook's Distance massima: 0.8298
# Visualizzo il caso più influente
data[idx_max, ]
## Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza Cranio
## 1551 35 1 NO 38 4370 315 374
## Tipo.parto Ospedale Sesso
## 1551 Nat osp3 F
Commenti:
# Femmina, terza gravidanza, 39 settimane.
# Lunghezza e Cranio impostate al valore mediano del campione.
new_case <- data.frame(
N.gravidanze = 3,
Gestazione = 39,
Lunghezza = median(data$Lunghezza), # 500 mm
Cranio = median(data$Cranio), # 340 mm
Sesso = factor("F", levels = levels(data$Sesso))
)
predict(mod_final, new_case, interval = "confidence") # CI sulla media
## fit lwr upr
## 1 3325.13 3301.329 3348.93
predict(mod_final, new_case, interval = "prediction") # intervallo sul singolo neonato
## fit lwr upr
## 1 3325.13 2786.035 3864.225
Commenti:
# Effetto di Gestazione e Fumo sul Peso
ggplot(data, aes(Gestazione, Peso, colour = Fumatrici)) +
geom_point(alpha = .3) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Peso vs Gestazione, per stato di fumo",
x = "Settimane di gestazione", y = "Peso (g)")
# Valori Osservati vs Predetti
data$pred <- fitted(mod_final)
ggplot(data, aes(pred, Peso)) +
geom_point(alpha = .3, colour = "#4C72B0") +
geom_abline(slope = 1, intercept = 0, colour = "red") +
labs(title = "Peso osservato vs predetto",
x = "Peso predetto (g)", y = "Peso osservato (g)")
Commenti:
Peso vs Gestazione Per Stato Di Fumo * Il grafico mostra una chiara correlazione positiva: in entrambi i gruppi il peso del neonato cresce linearmente all’aumentare delle settimane di gestazione. * La retta delle fumatrici è più corta e piatta (peso del neonato più basso), ma i dati delle fumatrici si concentrano solo sulle gestazioni più avanzate (~33 settimane in poi) e rappresentano appena il ~4% del campione (~104 casi). Peso Osservato vs Peso Predetto * I punti si dispongono attorno alla bisettrice rossa (osservato = predetto). Nella zona centrale (~2500–4000 g), dove sta la maggioranza dei neonati, la nuvola è compatta e ben allineata che implica buon adattamento del modello sui casi tipici. * La dispersione aumenta agli estremi: il modello è meno preciso sui casi rari (prematuri molto sottopeso e neonati più grandi della media). * Per i pesi predetti più bassi i punti stanno sopra la bisettrice e quindi il modello tende a sottostimare il peso dei neonati più piccoli (prevede valori troppo bassi rispetto al peso reale di 830–1000 g). * Si nota infine un outlier isolato in alto (peso reale molto superiore al predetto): uno dei casi anomali già segnalati nella diagnostica dei residui (tipo l’osservazione 1551).