knitr::opts_chunk$set(echo = TRUE)
df <- read.csv("/Users/chiaratombolini/Desktop/RSTUDIO/neonati.csv", stringsAsFactors = FALSE)

library(janitor)
## Warning: package 'janitor' was built under R version 4.3.3
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
df <- janitor::clean_names(df)

# Variabili categoriche come fattori
df$tipo_parto <- as.factor(df$tipo_parto)
df$ospedale   <- as.factor(df$ospedale)
df$sesso      <- as.factor(df$sesso)
df$fumatrici  <- as.factor(df$fumatrici)

# 1) Analisi descrittiva ----------------------------------
# Struttura + statistiche sintetiche
str(df)
## '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   : Factor w/ 2 levels "0","1": 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 ...
summary(df)
##    anni_madre     n_gravidanze     fumatrici   gestazione         peso     
##  Min.   : 0.00   Min.   : 0.0000   0:2396    Min.   :25.00   Min.   : 830  
##  1st Qu.:25.00   1st Qu.: 0.0000   1: 104    1st Qu.:38.00   1st Qu.:2990  
##  Median :28.00   Median : 1.0000             Median :39.00   Median :3300  
##  Mean   :28.16   Mean   : 0.9812             Mean   :38.98   Mean   :3284  
##  3rd Qu.:32.00   3rd Qu.: 1.0000             3rd Qu.:40.00   3rd Qu.:3620  
##  Max.   :46.00   Max.   :12.0000             Max.   :43.00   Max.   :4930  
##    lunghezza         cranio    tipo_parto ospedale   sesso   
##  Min.   :310.0   Min.   :235   Ces: 728   osp1:816   F:1256  
##  1st Qu.:480.0   1st Qu.:330   Nat:1772   osp2:849   M:1244  
##  Median :500.0   Median :340              osp3:835           
##  Mean   :494.7   Mean   :340                                 
##  3rd Qu.:510.0   3rd Qu.:350                                 
##  Max.   :565.0   Max.   :390
# Distribuzioni 
hist(df$peso,       main="Distribuzione Peso",       xlab="Peso (g)")

hist(df$lunghezza,  main="Distribuzione Lunghezza",  xlab="Lunghezza (cm)")

hist(df$anni_madre, main="Distribuzione Età madre",  xlab="Età (anni)")

hist(df$gestazione, main="Distribuzione Settimane",  xlab="Settimane di gestazione")

# Outlier per peso e lunghezza
outlier_iqr <- function(x) {
  x <- x[!is.na(x)]
  q1 <- quantile(x, 0.25); q3 <- quantile(x, 0.75)
  iqr <- q3 - q1
  low <- q1 - 1.5 * iqr; high <- q3 + 1.5 * iqr
  list(bounds=c(low=low, high=high))
}
oi_peso      <- outlier_iqr(df$peso)
oi_lunghezza <- outlier_iqr(df$lunghezza)
boxplot(df$peso, main="Boxplot Peso", ylab="Peso (g)")

boxplot(df$lunghezza, main="Boxplot Lunghezza", ylab="Lunghezza (cm)")

oi_peso
## $bounds
##  low.25% high.75% 
##     2045     4565
oi_lunghezza
## $bounds
##  low.25% high.75% 
##      435      555
# 2) Ipotesi ------------------------------------------------

# (a) In alcuni ospedali si fanno più parti cesarei
tab_parti <- table(df$ospedale, df$tipo_parto)
tab_parti
##       
##        Ces Nat
##   osp1 242 574
##   osp2 254 595
##   osp3 232 603
chisq.test(tab_parti)
## 
##  Pearson's Chi-squared test
## 
## data:  tab_parti
## X-squared = 1.0972, df = 2, p-value = 0.5778

Conclusione: non si rifiuta H₀ → nessuna evidenza che la frequenza di cesarei differisca tra ospedali nel campione.

# (b) Media del peso e della lunghezza uguali alla popolazione(presi valori medi su internet)

mu_peso       <- 3300   
mu_lunghezza  <- 500     

t.test(df$peso,      mu = mu_peso)
## 
##  One Sample t-test
## 
## data:  df$peso
## t = -1.516, df = 2499, p-value = 0.1296
## alternative hypothesis: true mean is not equal to 3300
## 95 percent confidence interval:
##  3263.490 3304.672
## sample estimates:
## mean of x 
##  3284.081
t.test(df$lunghezza, mu = mu_lunghezza)
## 
##  One Sample t-test
## 
## data:  df$lunghezza
## t = -10.084, df = 2499, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 500
## 95 percent confidence interval:
##  493.6598 495.7242
## sample estimates:
## mean of x 
##   494.692

Peso medio: coerente con il riferimento (≈ 3300 g), differenza non significativa e di entità pratica minima. Lunghezza media: significativamente più bassa del riferimento (≈ −5 mm)

# (c) Misure antropometriche diverse tra i sessi
t.test(peso      ~ sesso, data = df)   # peso M vs F
## 
##  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
t.test(lunghezza ~ sesso, data = df)   # lunghezza M vs F
## 
##  Welch Two Sample t-test
## 
## data:  lunghezza by sesso
## t = -9.582, df = 2459.3, 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.929470  -7.876273
## sample estimates:
## mean in group F mean in group M 
##        489.7643        499.6672
t.test(cranio    ~ sesso, data = df)   # cranio M vs F
## 
##  Welch Two Sample t-test
## 
## data:  cranio by sesso
## t = -7.4102, df = 2491.4, p-value = 1.718e-13
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
##  -6.089912 -3.541270
## sample estimates:
## mean in group F mean in group M 
##        337.6330        342.4486

differenze significative tra i sessi per peso, lunghezza e cranio (M > F).

library(moments)

# Indici di forma (asimmetria e curtosi) per il peso
skewness(df$peso, na.rm = TRUE)      # asimmetria
## [1] -0.6470308
kurtosis(df$peso, na.rm = TRUE) - 3  # curtosi centrata
## [1] 2.031532

L’asimmetria è negativa (skewness ≈ −0,65) e la curtosi in eccesso è ≈ +2,03. Interpretazione: c’è una coda a sinistra (alcuni pesi più bassi) e code più pesanti rispetto a una normale (presenza di casi non comuni).

# Scatterplot peso ~ settimane di gestazione
plot(df$gestazione, df$peso,
     xlab = "Settimane di gestazione",
     ylab = "Peso (g)",
     main = "Relazione Peso ~ Settimane Gestazione",
     pch = 19, col = "darkblue")

# Retta di regressione
abline(lm(peso ~ gestazione, data = df), col = "red")

#regressione multipla
mod_full <- lm(
  peso ~ anni_madre + n_gravidanze + fumatrici +
    gestazione + lunghezza + cranio +
    tipo_parto + ospedale + sesso,
  data = df
)
summary(mod_full)
## 
## Call:
## lm(formula = peso ~ anni_madre + n_gravidanze + fumatrici + gestazione + 
##     lunghezza + cranio + tipo_parto + ospedale + sesso, data = df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1124.40  -181.66   -14.42   160.91  2611.89 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -6738.4762   141.3087 -47.686  < 2e-16 ***
## anni_madre        0.8921     1.1323   0.788   0.4308    
## n_gravidanze     11.2665     4.6608   2.417   0.0157 *  
## fumatrici1      -30.1631    27.5386  -1.095   0.2735    
## gestazione       32.5696     3.8187   8.529  < 2e-16 ***
## lunghezza        10.2945     0.3007  34.236  < 2e-16 ***
## cranio           10.4707     0.4260  24.578  < 2e-16 ***
## tipo_partoNat    29.5254    12.0844   2.443   0.0146 *  
## ospedaleosp2    -11.2095    13.4379  -0.834   0.4043    
## ospedaleosp3     28.0958    13.4957   2.082   0.0375 *  
## sessoM           77.5409    11.1776   6.937 5.08e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 273.9 on 2489 degrees of freedom
## Multiple R-squared:  0.7289, Adjusted R-squared:  0.7278 
## F-statistic: 669.2 on 10 and 2489 DF,  p-value: < 2.2e-16
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 = df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1113.18  -181.16   -16.58   161.01  2620.19 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   -6707.4293   135.9438 -49.340  < 2e-16 ***
## n_gravidanze     12.3619     4.3325   2.853  0.00436 ** 
## gestazione       31.9909     3.7896   8.442  < 2e-16 ***
## lunghezza        10.3086     0.3004  34.316  < 2e-16 ***
## cranio           10.4922     0.4254  24.661  < 2e-16 ***
## tipo_partoNat    29.2803    12.0817   2.424  0.01544 *  
## ospedaleosp2    -11.0227    13.4363  -0.820  0.41209    
## ospedaleosp3     28.6408    13.4886   2.123  0.03382 *  
## sessoM           77.4412    11.1756   6.930 5.36e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 273.9 on 2491 degrees of freedom
## Multiple R-squared:  0.7287, Adjusted R-squared:  0.7278 
## F-statistic: 836.3 on 8 and 2491 DF,  p-value: < 2.2e-16
BIC(mod_full, mod_step)
##          df      BIC
## mod_full 12 35241.84
## mod_step 10 35228.03
R2   <- summary(mod_step)$r.squared
res  <- residuals(mod_step)
RMSE <- sqrt(mean(res^2, na.rm = TRUE))
R2; RMSE
## [1] 0.7286934
## [1] 273.4227
par(mfrow = c(2, 2))
plot(mod_step)

# Diagnostica test
lmtest::bptest(mod_step)

## 
##  studentized Breusch-Pagan test
## 
## data:  mod_step
## BP = 91.768, df = 8, p-value < 2.2e-16
shapiro.test(residuals(mod_step))
## 
##  Shapiro-Wilk normality test
## 
## data:  residuals(mod_step)
## W = 0.97408, p-value < 2.2e-16
car::outlierTest(mod_step)
##       rstudent unadjusted p-value Bonferroni p
## 1551 10.004278         3.9642e-23   9.9104e-20
## 155   5.046640         4.8210e-07   1.2053e-03
## 1306  4.872419         1.1716e-06   2.9291e-03
# Punti influenti
par(mfrow = c(1, 1), mar=c(5,4,2,1))
plot(cooks.distance(mod_step), main = "Distanza di Cook")

lev <- hatvalues(mod_step)
par(mar=c(5,4,2,1))
plot(lev, main = "Leverage"); abline(h = 2 * mean(lev), col = "red")

Bontà di adattamento: R² ≈ 0,729, RMSE ≈ 273 g → ~73% della variabilità del peso spiegata; errore medio delle previsioni ~±273 g. Effetti (a parità delle altre variabili): Gestazione: circa +32 g per settimana. Sesso (M vs riferimento F): circa +77 g. Lunghezza: circa +10,3 g per mm. Cranio: circa +10,5 g per mm. n_gravidanze: effetto positivo, ≈ +12 g per gravidanza.

# PREVISIONI
moda <- function(x) { ux <- na.omit(x); if (!length(ux)) return(NA); names(sort(table(ux), decreasing = TRUE))[1] }
typ_num <- function(x) median(x, na.rm = TRUE)

newx <- data.frame(
  anni_madre   = if ("anni_madre"   %in% names(df)) typ_num(df$anni_madre)   else NA_real_,
  n_gravidanze = if ("n_gravidanze" %in% names(df)) 3                         else NA_real_,
  fumatrici    = if ("fumatrici"    %in% names(df)) factor(moda(df$fumatrici), levels = levels(df$fumatrici)) else NA,
  gestazione   = if ("gestazione"   %in% names(df)) 39                        else NA_real_,
  lunghezza    = if ("lunghezza"    %in% names(df)) typ_num(df$lunghezza)     else NA_real_,
  cranio       = if ("cranio"       %in% names(df)) typ_num(df$cranio)        else NA_real_,
  tipo_parto   = if ("tipo_parto"   %in% names(df)) factor(moda(df$tipo_parto), levels = levels(df$tipo_parto)) else NA,
  ospedale     = if ("ospedale"     %in% names(df)) factor(moda(df$ospedale), levels = levels(df$ospedale))     else NA,
  sesso        = if ("sesso"        %in% names(df)) factor("F", levels = levels(df$sesso))                      else NA
)

nm_needed <- all.vars(formula(mod_step))[-1]
missing_cols <- setdiff(nm_needed, colnames(newx))
for (mc in missing_cols) {
  if (mc %in% names(df)) {
    newx[[mc]] <- if (is.numeric(df[[mc]])) typ_num(df[[mc]]) else factor(moda(df[[mc]]), levels = levels(df[[mc]]))
  } else {
    newx[[mc]] <- NA
  }
}
newx <- newx[, nm_needed, drop = FALSE]

pred_point <- predict(mod_step, newdata = newx)
pred_pred  <- predict(mod_step, newdata = newx, interval = "prediction")  # singola osservazione
pred_conf  <- predict(mod_step, newdata = newx, interval = "confidence")  # media attesa

pred_point; pred_pred; pred_conf
##        1 
## 3317.222
##        fit    lwr      upr
## 1 3317.222 2779.3 3855.145
##        fit      lwr      upr
## 1 3317.222 3287.977 3346.467
# === VISUALIZZAZIONI--------------

# Modello: peso ~ gestazione * fumatrici 
m_vis <- lm(peso ~ gestazione * fumatrici, data = df)
summary(m_vis)  
## 
## Call:
## lm(formula = peso ~ gestazione * fumatrici, data = df)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1609.03  -289.03   -11.54   280.97  1898.44 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           -3240.771    178.861 -18.119   <2e-16 ***
## gestazione              167.495      4.585  36.534   <2e-16 ***
## fumatrici1             1343.426   1164.746   1.153    0.249    
## gestazione:fumatrici1   -36.764     29.646  -1.240    0.215    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 422.9 on 2496 degrees of freedom
## Multiple R-squared:  0.352,  Adjusted R-squared:  0.3513 
## F-statistic:   452 on 3 and 2496 DF,  p-value: < 2.2e-16
# Predizioni su una griglia di gestazione × fumatrici
gest_vals <- seq(min(df$gestazione, na.rm = TRUE),
                 max(df$gestazione, na.rm = TRUE), by = 1)
fum_lvls  <- levels(df$fumatrici)
grid <- expand.grid(gestazione = gest_vals, fumatrici = fum_lvls)
grid$yhat <- predict(m_vis, newdata = grid)

# Grafico con due linee (una per livello di fumo)
par(mfrow = c(1,1), mar = c(4,4,2,1))
plot(NA,
     xlim = range(gest_vals),
     ylim = range(grid$yhat, na.rm = TRUE),
     xlab = "Settimane di gestazione",
     ylab = "Peso previsto (g)",
     main = "Peso previsto vs Gestazione per livello di fumo (modello semplice)")
for (fv in fum_lvls) {
  sel <- grid$fumatrici == fv
  lines(grid$gestazione[sel], grid$yhat[sel], lwd = 2)
}
legend("topleft", legend = fum_lvls, lwd = 2, bty = "n", title = "Fumatrici")

commento al grafico:Le due linee (non fumatrice/fumatrice) crescono con le settimane (più gestazione ⇒ più peso). Le linee non parallele e l’incrocio indicano interazione: l’effetto del fumo dipende dalla durata della gestazione.

CONCLUSIONI: nessuna differenza di cesarei tra ospedali; peso campione allineato a 3300 g; differenze tra sessi nette e significative per tutte le misure. Modello: buona capacità esplicativa/predittiva (R²~0,73; RMSE~273 g). Variabili chiave: gestazione, misure antropometriche (lunghezza, cranio) e sesso. Diagnostica: presenza di eteroschedasticità → preferibili SE robusti; residui non normali (attesi con n grande)..