Avendo ricevuto la richiesta dalla Neonatal Health Solutions di un modello per poter prevedere il peso dei neonati e ricevuti i dati, ho deciso di iniziare con lo studio dei dati a mio dire più importanti. Questo, includendo la visualizzazione delle combinazioni dei dati per capire l’influenza degli stessi sul peso dei neonati, oltre che comprendere la situazione per le madri fumatrici e notare le differenze di gestazione.
Variabili del dataset:
Età madre : quantitativa continua
N. gravidanze : quantitativa discreta
Fumatrice : qualitativa nominale
Gestazione : quantitativa continua
Peso : quantitativa continua
Diametro/lunghezza del cranio : quantitativa continua
Tipo di parto : qualitativa nominale
Ospedale di nascita : qualitativa nominale
Sesso del neonato : qualitativa nominale
Inzio con il preparare delle funzioni utili per il calcolo degli indici più importanti per le varie variabili.
library(ggplot2)
library(dplyr)
##
## Caricamento pacchetto: 'dplyr'
## I seguenti oggetti sono mascherati da 'package:stats':
##
## filter, lag
## I seguenti oggetti sono mascherati da 'package:base':
##
## intersect, setdiff, setequal, union
library(moments)
library(car)
## Caricamento del pacchetto richiesto: carData
##
## Caricamento pacchetto: 'car'
## Il seguente oggetto è mascherato da 'package:dplyr':
##
## recode
library(lmtest)
## Caricamento del pacchetto richiesto: zoo
##
## Caricamento pacchetto: 'zoo'
## I seguenti oggetti sono mascherati da 'package:base':
##
## as.Date, as.Date.numeric
library(rgl)
library(knitr)
library(MASS)
##
## Caricamento pacchetto: 'MASS'
## Il seguente oggetto è mascherato da 'package:dplyr':
##
## select
library(Metrics)
df = read.csv("neonati.csv", sep = ",")
n = nrow(df)
#Indice di eterogeneità di Gini
gini.index = function(x){
ni=table(x)
fi=ni/length(x)
fi2=fi**2
j=length(table(x))
gini = 1-sum(fi2)
gini.normalizzato = gini/((j-1)/j)
return(gini.normalizzato)
}
#curtosi
kurtosi.index = function(x){
mu = mean(x)
sigma = sd(x)
n = length(x)
m4 = sum((x-mu)**4)/n
kurtosi.index = m4/sigma**4 - 3
return(kurtosi.index)
}
quant = function(x) {
sd_val = sd(x)
var_val = var(x)
kurt_val = kurtosi.index(x)
return(c(sd = sd_val, var = var_val, kurt = kurt_val))
}
In seguito sono andato a calcolare il summary dell’intero dataset, per avere un idea generale dei dati presenti, poi, sono andato a calcolare indici extra che possono essere util, pulisco i dati dalle variabili Na, e le età più estreme delle madri.
df = df[!df$Anni.madre <= 10, ]
df = na.omit(df)
summary(df)
## Anni.madre N.gravidanze Fumatrici Gestazione
## Min. :13.00 Min. : 0.0000 Min. :0.00000 Min. :25.00
## 1st Qu.:25.00 1st Qu.: 0.0000 1st Qu.:0.00000 1st Qu.:38.00
## Median :28.00 Median : 1.0000 Median :0.00000 Median :39.00
## Mean :28.19 Mean : 0.9816 Mean :0.04163 Mean :38.98
## 3rd Qu.:32.00 3rd Qu.: 1.0000 3rd Qu.:0.00000 3rd Qu.:40.00
## Max. :46.00 Max. :12.0000 Max. :1.00000 Max. :43.00
## Peso Lunghezza Cranio Tipo.parto
## Min. : 830 Min. :310.0 Min. :235 Length:2498
## 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:2498 Length:2498
## Class :character Class :character
## Mode :character Mode :character
##
##
##
peso = quant(df$Peso)
lungh = quant(df$Lunghezza)
cranio = quant(df$Cranio)
kable(peso)
| x | |
|---|---|
| sd | 5.252294e+02 |
| var | 2.758659e+05 |
| kurt | 2.024728e+00 |
kable(lungh)
| x | |
|---|---|
| sd | 26.328847 |
| var | 693.208160 |
| kurt | 6.473341 |
gini_gest = gini.index(df$Gestazione)
gest = c(quant(df$Gestazione), gini = gini_gest)
kable(gest)
| x | |
|---|---|
| sd | 1.8689503 |
| var | 3.4929751 |
| kurt | 8.2465059 |
| gini | 0.8475314 |
kable(cranio)
| x | |
|---|---|
| sd | 16.429469 |
| var | 269.927460 |
| kurt | 2.940112 |
Vedendo questi risultati, ho consultato un grafico per avere una visione chiara delle distribuzioni tra peso, sesso, numero di gravidanze passate della madre ed il tipo di parto necessario per il neonato. In più, per la gestazione possiamo notare un gini index quasi uniforme.
ggplot(data.frame(x = rnorm(2498, mean(df$Peso), peso[1]), y = df$Sesso), aes(x = x, fill = y))+
geom_density(alpha = .5, position = "identity")+
geom_vline(aes(xintercept = mean(df$Peso)), color = "red")+
theme_minimal()+
labs(
title = "Distribuzione normale del peso",
x = "Peso",
y = "Densità",
fill = "Sesso"
)
ggplot(df)+
geom_bar(aes(x = N.gravidanze, fill = Tipo.parto))+
theme_minimal()+
labs(
title = "Tipo di parto per numero di gravidanze già fatte",
x = "Numero Gravidanze",
y = "Conto",
fil = "Tipo Parto"
)
Possiamo notare che tra maschi e femmine c’è una buona differenza nel peso, graficamente, la distribuzione maschile si può notare essere, infatti, più alta e sottile ai latim, invece quella femminile è più piccola e stretta, entrambe presentano delle lievi distorsioni lunga la distribuzione.
Capiamo quindi che i maschi, hanno una maggioranza di peso di media 3300 grammi, con il minimo che si aggira sulla media dei 1000 grammi, ed un massimo attorno alla media dei 5500 grammi.
Le femmine, invece, notiamo che la loro media di picco si aggira alla media di 3600 grammi, con il minimo al di sotto della media dei 1000 grammi ed il massimo, come per i maschi, attorno alla media dei 5500 grammi.
Il secondo grafico rappresenta il rapporto tra il tipo di parto ed il numero di gravidanze che la madre ha già avuto. Notiamo che il parto cesareo all’inizio con le prime gravidanze arriva ad essere molto più alto rispetto al parto cesareo, ma con un numero di gravidanze più alto arriva a scomparire del tutto.
Pensando che in alcuni ospedali ci sia una maggioranza di parti cesarei possiamo calcolare con il test di Chisq il tipo di parto in relazione all’ospedale, ed in seguito, associare questo ad un grafico a barre che mostra la differenza in altezza delle due colonne che rappresentano il tipo di parto per ogni ospedale.
Il test ci risulta un P-Value di ben 0.5778, dimostra che effettivamente la nostra ipotesi è corretta. Osservando il grafico otteniamo anche la conferma visiva, notando come nel secondo ospedali ci sia effettivamente un numero più elevato di parti cesarei rispetto agli altri due.
csq = chisq.test(df$Tipo.parto, df$Ospedale)
csq
##
## Pearson's Chi-squared test
##
## data: df$Tipo.parto and df$Ospedale
## X-squared = 1.083, df = 2, p-value = 0.5819
ggplot(df)+
geom_bar(aes(x = Ospedale, fill = Tipo.parto))+
theme_minimal()+
labs(
title = "Quantità dei tipi di parto negli ospedali",
x = "Ospedali",
y = "Conto",
fill = "Tipo Parto"
)
Per capire se il nostro campione può essere un esempio corretto rispetto alla popolazione, possiamo calcolare con un t-test se la media del campione è significativamente uguale a quella della popolazione, e poi creiamo ancora un grafico a barre per mostrare la differenza in altezza delle due classi peso e lunghezza tra campione e popolazione. Ho recuperato le medie di peso e lunghezza da questo sito web che ci garantisce un peso medio di 3300 grammi ed una lunghezza media di 500 millimetri.
media_pop_peso = 3300
media_pop_lung = 500
media_peso = mean(df$Peso)
media_lung = mean(df$Lunghezza)
kable(cbind(media_peso, media_lung))
| media_peso | media_lung |
|---|---|
| 3284.184 | 494.6958 |
t.test(df$Peso, mu = media_pop_peso)
##
## One Sample t-test
##
## data: df$Peso
## t = -1.505, df = 2497, p-value = 0.1324
## alternative hypothesis: true mean is not equal to 3300
## 95 percent confidence interval:
## 3263.577 3304.791
## sample estimates:
## mean of x
## 3284.184
t.test(df$Lunghezza, mu = media_pop_lung)
##
## One Sample t-test
##
## data: df$Lunghezza
## t = -10.069, df = 2497, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 500
## 95 percent confidence interval:
## 493.6628 495.7287
## sample estimates:
## mean of x
## 494.6958
ggplot(df)+
geom_boxplot(aes(y = Peso))+
geom_hline(aes(yintercept = media_pop_peso), color = "red")+
theme_minimal()+
labs(
title = "T.test tra il peso medio della popolazione e del campione",
y = "Peso"
)
ggplot(df)+
geom_boxplot(aes(y = Lunghezza))+
geom_hline(aes(yintercept = media_pop_lung), color = "red")+
theme_minimal()+
labs(
title = "T.test tra la lunghezza media della popolazione e del campione",
y = "Lunghezza"
)
Possiamo vedere con questi t-test, che ci ritornano un P-value di 0.1296 e per la lunghezza <0.00000000000000022, che la differenza tra la media campione e media popolazione non è significante per poter rendere inaffidabile il campione. Nei grafici dedicati, infatti, possiamo avere un’ulteriore sicurezza su questi risultati, vedendo come la linea rossa, che rappresenta la media in grammi della popolazione, sia quasi perfettamente nella stessa posizione della media del nostro campione.
Ora dobbiamo controllare se le misure delle varie parti del corpo tra maschi e femmine siano significativamente diverse. Usando la misura del cranio possiamo calcolare con il T-test se tra maschi e femmine ci sono differenze.
t_test_cranio = t.test(df$Cranio ~ df$Sesso)
t_test_cranio
##
## Welch Two Sample t-test
##
## data: df$Cranio by df$Sesso
## t = -7.4366, df = 2489.4, p-value = 1.414e-13
## alternative hypothesis: true difference in means between group F and group M is not equal to 0
## 95 percent confidence interval:
## -6.110504 -3.560417
## sample estimates:
## mean in group F mean in group M
## 337.6231 342.4586
ggplot(df)+
geom_bar(aes(Cranio, fill = Sesso))+
theme_minimal()+
scale_y_continuous(breaks = seq(10, 250, 20))+
labs(
title = "Confronto tra le misure del cranio maschili e femminili",
x = "Misurazioni Cranio",
y = "Conto",
fill = "Sesso"
)
Anche con questo test, che ci riporta un P-value veramente insignificante, del valore di 0,001, ci fa capire, che non ci sono differenze significanti tra i due sessi. Come con le precedenti due domande, possiamo avere la sicurezza visiva utilizzando un grafico a barre, che ci mostra, che nonostante siano registrate delle misure del cranio molto più piccole per le femmine rispetto che per i maschi, queste non sono di significatività elevata per far pensare che le misure antropometriche possano essere differenti tra i due sessi.
Considerando che il nostro modello dovrà prevedere la classe del peso, ho deciso di ristrutturare il dataset permettendo alle varie variabili di rientrare in delle categorie specifiche di peso.
Ho diviso il dataset in 5 classi di peso, queste varianti da sotto i 1000 grammi fino ad arrivare sotto ai 5000 grammi. Con questo, ho deciso di andare a controllare la variabile della gestazione, per avere la conferma sulla sua significatività di interazione sulla nostra classe peso, e viceversa, con un grafico diviso per sesso.
df$peso_cut = cut(df$Peso, breaks = 5)
ggplot(df)+
geom_boxplot(aes(x = peso_cut, y = Gestazione, group = Sesso, fill = Sesso))+
theme_minimal()+
scale_x_discrete(labels = c("< 1000", "< 2000", "< 3000", "< 4000", "< 5000"))+
labs(
title = "Gestazione per peso in base al sesso",
x = "Classi di peso (in grammi)",
y = "Gestazione"
)
ggplot(df)+
geom_point(aes(x = format(peso_cut, scientific = FALSE), y = Gestazione, fill = Sesso, color = Sesso), position = "jitter")+
scale_x_discrete(labels = c("< 1000", "< 2000", "< 3000", "< 4000", "< 5000"))+
labs(
title = "Gestazione per peso in base al sesso",
x = "Classi di peso (in grammi)",
y = "Gestazione"
)+
theme_minimal()
Notiamo che nonostante si possa pensare il contrario, un peso più elevato non è strettamente legato ad una gestazione più lunga, al contrario, si registrano gestazioni più grandi per le classi di peso tra i <2000 grammi e i <3000 grammi, con una grande differenza fra la gestazione di quelle fasce di peso tra maschi e femmine, con le femmine che richiedono una gestazione molto più alta e sono molto più dense nel grafico.
Ora, faccio lo stesso processo anche per la lunghezza, anche qui in 5 classi, a partire dai 310mm - 361mm ad arrivare alla classe dei 514mm - 565mm. Per parità rispetto alla classe del peso, ho deciso di registrare la gestazione divisa per la lunghezza.
df$lung_cut = cut(df$Lunghezza, breaks = 5)
ggplot(df)+
geom_boxplot(aes(x = lung_cut, y = Gestazione, group = Sesso, fill = Sesso))+
theme_minimal()+
labs(
title = "Gestazione per lunghezza in base al sesso",
x = "Classi di Lunghezza",
y = "Gestazione"
)
Possiamo vedere che nonostante per la classe peso non serviva essere di una classe alta per avere una gestazione elevata, per la lunghezza invece la gestazione più alta è presente nella lunghezza compresa tra i 463mm - 514mm, e la classe più alta a seguire. Anche qui, notiamo che le femmine hanno una gestazione molto più alta rispetto al genere maschile.
Come piccolo extra, ho deciso di andare a controllare se le madri fumatrici avessero una gestazione più o meno elevata rispetto alle madri non fumatrici.
ggplot(df, aes(x = Fumatrici, y = Gestazione, fill = Sesso))+
stat_summary(fun = "mean", geom = "bar", position = "dodge")+
theme_minimal()+
scale_x_continuous(breaks = seq(0, 1, 1))+
labs(
title = "Gestazione per donne fumatrici in base al sesso",
x = "Fumatrici",
y = "Gestazione",
fill = "Sesso"
)
Notiamo che questo grafico le madri che non fumano tendono ad aver una gestazione molto più alta rispetto alle madri che fumano. Con una superiorità per il sesso maschile nelle settimane totali di gestazioni in entrambi i casi.
Prima di creare il modello voglio andare a calcolare la correlazione tra le varie variabili del dataset con la classe peso.
cor.test(df$Peso, df$Gestazione)
##
## Pearson's product-moment correlation
##
## data: df$Peso and df$Gestazione
## t = 36.694, df = 2496, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.5658780 0.6168568
## sample estimates:
## cor
## 0.5919592
cor.test(df$Peso, df$N.gravidanze)
##
## Pearson's product-moment correlation
##
## data: df$Peso and df$N.gravidanze
## t = 0.11377, df = 2496, p-value = 0.9094
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.03694459 0.04149182
## sample estimates:
## cor
## 0.002277118
cor.test(df$Peso, df$Lunghezza)
##
## Pearson's product-moment correlation
##
## data: df$Peso and df$Lunghezza
## t = 65.71, df = 2496, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.7812121 0.8099730
## sample estimates:
## cor
## 0.7960415
cor.test(df$Peso, df$Cranio)
##
## Pearson's product-moment correlation
##
## data: df$Peso and df$Cranio
## t = 49.642, df = 2496, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.6845483 0.7240475
## sample estimates:
## cor
## 0.7048438
cor.test(df$Peso, df$Anni.madre)
##
## Pearson's product-moment correlation
##
## data: df$Peso and df$Anni.madre
## t = -1.1885, df = 2496, p-value = 0.2348
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.06294109 0.01545144
## sample estimates:
## cor
## -0.02378138
Possiamo notare che:
Per la gestazione abbiamo una correlazione media
Per la lunghezza e la misura del cranio abbiamo una correlazione grande
Per il numero di gravidanze, la variabile delle fumatrici e gli anni della madre abbiamo una correlazione nulla
In seguito vado a rappresentare queste correlazioni usando la funzione pairs().
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
par(usr = c(0, 1, 0, 1))
r <- abs(cor(x, y))
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 * r)
}
num_data = cbind(Anni=df$Anni.madre, N.Grav = df$N.gravidanze, Fumatrici = df$Fumatrici, Gestazione = df$Gestazione, Peso=df$Peso,Lungh = df$Lunghezza, Cranio = df$Cranio)
pairs(num_data,upper.panel = panel.smooth, lower.panel = panel.cor)
Una volta confermate, andiamo finalmente a creare il nostro modello.
mod1 = lm(Peso ~ Gestazione + Lunghezza + Anni.madre + Fumatrici + Cranio + N.gravidanze + Sesso, data = df)
best = stepAIC(mod1, direction = "both", trace= TRUE)
## Start: AIC=28064.05
## Peso ~ Gestazione + Lunghezza + Anni.madre + Fumatrici + Cranio +
## N.gravidanze + Sesso
##
## Df Sum of Sq RSS AIC
## - Anni.madre 1 44292 187949505 28063
## - Fumatrici 1 91474 187996688 28063
## <none> 187905214 28064
## - N.gravidanze 1 446756 188351970 28068
## - Sesso 1 3658879 191564093 28110
## - Gestazione 1 5587942 193493156 28135
## - Cranio 1 45789523 233694736 28607
## - Lunghezza 1 87128339 275033553 29014
##
## Step: AIC=28062.64
## Peso ~ Gestazione + Lunghezza + Fumatrici + Cranio + N.gravidanze +
## Sesso
##
## Df Sum of Sq RSS AIC
## - Fumatrici 1 92548 188042054 28062
## <none> 187949505 28063
## + Anni.madre 1 44292 187905214 28064
## - N.gravidanze 1 643981 188593487 28069
## - Sesso 1 3666800 191616305 28109
## - Gestazione 1 5544825 193494331 28133
## - Cranio 1 46056754 234006260 28608
## - Lunghezza 1 87116561 275066067 29012
##
## Step: AIC=28061.87
## Peso ~ Gestazione + Lunghezza + Cranio + N.gravidanze + Sesso
##
## Df Sum of Sq RSS AIC
## <none> 188042054 28062
## + Fumatrici 1 92548 187949505 28063
## + Anni.madre 1 45366 187996688 28063
## - N.gravidanze 1 621053 188663107 28068
## - Sesso 1 3650790 191692844 28108
## - Gestazione 1 5477493 193519547 28132
## - Cranio 1 46098547 234140601 28608
## - Lunghezza 1 87532691 275574744 29015
summary(best)
##
## Call:
## lm(formula = Peso ~ Gestazione + Lunghezza + Cranio + N.gravidanze +
## Sesso, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1149.37 -180.98 -15.57 163.69 2639.09
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6681.7251 135.8036 -49.201 < 2e-16 ***
## Gestazione 32.3827 3.8008 8.520 < 2e-16 ***
## Lunghezza 10.2455 0.3008 34.059 < 2e-16 ***
## Cranio 10.5410 0.4265 24.717 < 2e-16 ***
## N.gravidanze 12.4554 4.3416 2.869 0.00415 **
## SessoM 77.9807 11.2111 6.956 4.47e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274.7 on 2492 degrees of freedom
## Multiple R-squared: 0.727, Adjusted R-squared: 0.7265
## F-statistic: 1327 on 5 and 2492 DF, p-value: < 2.2e-16
anova(best, mod1)
## Analysis of Variance Table
##
## Model 1: Peso ~ Gestazione + Lunghezza + Cranio + N.gravidanze + Sesso
## Model 2: Peso ~ Gestazione + Lunghezza + Anni.madre + Fumatrici + Cranio +
## N.gravidanze + Sesso
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 2492 188042054
## 2 2490 187905214 2 136840 0.9067 0.404
BIC(best, mod1)
## df BIC
## best 7 35193.65
## mod1 9 35207.48
Utilizzando la funzione stepAIC con entrambe le direzioni impostate, abbiamo automaticamente testato diversi tipi di modello andando a rimuovere e riaggiungere le varie variabili finchè non abbiamo trovato il modello più ottimizzato. Per andare a verificarlo manualmente, possiamo controllare usando il BIC e l’ANOVA, vedendo quale delle due tra il modello che ci ha dato la funzione, ed il modello originario ha lo score più basso. In più, con la funzione stepAIC possiamo già vedere nelle varie prove che ha fatto quale score ha ottenuto ogni modello.
Guardando invece i coefficienti del modello, notiamo che per ogni settimana di gestazione in più il peso aumenta in media di 32.38 grammi , per i maschi, 77.98 grammi in più delle femmine, la lunghezza di 10.24mm, ed il diametro del cranio di 10.54, in più, a seconda del n. di gravidanze il peso medio sarà di 12.45 grammi in più.
Ora che abbiamo il modello possiamo fare le valutazioni, partiamo con il fare un plot per i 4 grafici principali:
La linearità tra residui e valori predetti
Controllare se i dati residui sono normali
Controllare l’omoschedasticità dei dati
Individuare dati estremi influenti
par(mfrow = c(2, 2))
plot(best)
Per il primo grafico, vediamo che la distribuzione dei residui rispetto alle predizioni del modello non è una dispersione casuale, ma è più una macchia di dati con una “coda”, cosa che ci fa capire esserci non-linearità tra i dati.
Nel secondo grafico, per osservare la normalità dei dati residui, ci mostra una linea retta di dati curva nelle code. Nel caso di questo dataset penso sia legato alla distribuzione dei dati non perfettamente gaussiana.
Nel terzo grafico, vediamo che i punti del grafico seguono più o meno, la stessa distribuzione del primo grafico, in questo caso però sono segno di omoschedasticità tra i dati.
Nell’ultimo notiamo che maggior parte dei dati rimane nel range della distanza di cook’s con un paio di outliers che vanno oltre la distanza minima, mentre un singolo dato rimane nella soglia di accettazione, in alto a destra, nonostante questo però, non mi sento di bocciare il modello.
lev = hatvalues(best)
par(mfrow = c(1, 1))
plot(lev)
p = sum(lev)
soglia = 2* p/n
abline(h = soglia, col = 2)
In seguito abbiamo il grafico dedicato all’influenza delle osservazioni sulla stima del modello, possiamo notare come non ci sono troppi dati estremi che ci potrebbero far pensare ad una brutta uscita del modello.
lev[lev>soglia]
## 13 15 34 67 89 96
## 0.005632888 0.007056483 0.006748974 0.005896189 0.012817563 0.005351869
## 101 106 131 134 151 155
## 0.007528094 0.014487904 0.007237755 0.007553514 0.010889886 0.007209736
## 161 189 190 204 205 206
## 0.020341133 0.004894598 0.005366831 0.014494112 0.005351828 0.009482503
## 220 294 305 310 312 315
## 0.007403130 0.005914307 0.005445189 0.028815300 0.013173723 0.005386836
## 378 440 442 445 486 492
## 0.015942080 0.005405733 0.007725708 0.007511227 0.005165714 0.008274392
## 497 516 582 587 592 614
## 0.005167522 0.013080707 0.011667393 0.008415872 0.006385013 0.005300091
## 638 656 657 684 697 702
## 0.006693153 0.005934494 0.005323517 0.008825948 0.005864920 0.005203163
## 729 748 750 757 765 805
## 0.005024448 0.008567254 0.006943755 0.008146487 0.006076412 0.014358658
## 828 893 895 913 928 946
## 0.007180179 0.005076266 0.005297643 0.005574016 0.022745493 0.006910965
## 947 949 956 985 1008 1014
## 0.008409518 0.004801229 0.007791530 0.007040035 0.005343994 0.008474086
## 1049 1067 1091 1106 1130 1166
## 0.004956561 0.008467035 0.008940030 0.005967511 0.031739177 0.005513581
## 1181 1188 1200 1219 1238 1248
## 0.005678043 0.006481533 0.005493009 0.030697778 0.005912496 0.014631359
## 1273 1291 1293 1311 1321 1325
## 0.007089553 0.006118589 0.006074423 0.009626391 0.009295311 0.004857340
## 1356 1357 1385 1395 1400 1402
## 0.005306940 0.006967713 0.012641828 0.005129491 0.005932524 0.004816704
## 1411 1420 1428 1429 1450 1505
## 0.008049539 0.005156670 0.008195421 0.021758961 0.015106684 0.013334256
## 1551 1553 1556 1573 1593 1606
## 0.048802841 0.008507417 0.005923458 0.005049368 0.005624961 0.005009312
## 1610 1617 1619 1628 1686 1693
## 0.008725821 0.004869997 0.015069038 0.005070717 0.009356578 0.005079185
## 1701 1712 1718 1727 1735 1780
## 0.010846383 0.006993461 0.006961226 0.013303625 0.004886226 0.025544997
## 1781 1809 1827 1868 1892 1962
## 0.016833696 0.008711082 0.006068655 0.005206137 0.005333985 0.005541287
## 1967 1977 2037 2040 2046 2086
## 0.005339716 0.006928794 0.004890003 0.011504028 0.005471894 0.013194769
## 2089 2098 2114 2115 2120 2140
## 0.006293791 0.005097113 0.013318873 0.011779730 0.018667270 0.006244737
## 2146 2148 2149 2157 2175 2200
## 0.005804705 0.007930323 0.013589469 0.005910248 0.032531736 0.011679031
## 2215 2216 2220 2221 2224 2225
## 0.004894044 0.008120291 0.005415586 0.021633907 0.005841119 0.005593576
## 2244 2257 2307 2317 2318 2337
## 0.006929530 0.006171101 0.013972901 0.007677230 0.004834368 0.005230839
## 2359 2408 2422 2436 2437 2452
## 0.010068259 0.009702475 0.021536269 0.004986609 0.023951342 0.023848222
## 2458 2471 2478
## 0.008509142 0.020905930 0.005777111
plot(rstudent(best))
abline(h = c(-2, 2), col = 2)
outlierTest(best)
## rstudent unadjusted p-value Bonferroni p
## 1551 10.046230 2.6345e-23 6.5810e-20
## 155 5.025345 5.3818e-07 1.3444e-03
## 1306 4.824963 1.4848e-06 3.7092e-03
Con questo invece calcoliamo se i valori di leverage rimangono all’interno del nostro range dei dati residui dalla funzione rstudent(), questo ci aiuta ad identificare osservazioni “strane” andando a visualizzare la varianza del modello, nel nostro caso possiamo accettare il modello, non avendo troppe osservazioni estreme all’infuori della nostra soglia.
Per avere una sicurezza finale, andiamo a fare il bptest, che ci presenta un p-value basso, quindi notiamo che il modello ha un pò di problemi di omoschedasticità, il dwtest, che ci presenta dei valori che ci fanno notare come il modello non ha problemi di autocorrelazione tra i valori residui, il test di shapiro, che ci presenta un p-value basso, che spiega che i nostri residui non seguono una distribuzione normale, ed infine, calcoliamo l’rmse, che ci presenta un valore basso rispetto alla scala del peso dei nostri dati.
bptest(best)
##
## studentized Breusch-Pagan test
##
## data: best
## BP = 90.297, df = 5, p-value < 2.2e-16
dwtest(best)
##
## Durbin-Watson test
##
## data: best
## DW = 1.9532, p-value = 0.1209
## alternative hypothesis: true autocorrelation is greater than 0
shapiro.test(residuals(best))
##
## Shapiro-Wilk normality test
##
## data: residuals(best)
## W = 0.97414, p-value < 2.2e-16
summary(best)
##
## Call:
## lm(formula = Peso ~ Gestazione + Lunghezza + Cranio + N.gravidanze +
## Sesso, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1149.37 -180.98 -15.57 163.69 2639.09
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6681.7251 135.8036 -49.201 < 2e-16 ***
## Gestazione 32.3827 3.8008 8.520 < 2e-16 ***
## Lunghezza 10.2455 0.3008 34.059 < 2e-16 ***
## Cranio 10.5410 0.4265 24.717 < 2e-16 ***
## N.gravidanze 12.4554 4.3416 2.869 0.00415 **
## SessoM 77.9807 11.2111 6.956 4.47e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274.7 on 2492 degrees of freedom
## Multiple R-squared: 0.727, Adjusted R-squared: 0.7265
## F-statistic: 1327 on 5 and 2492 DF, p-value: < 2.2e-16
kable(rmse(df$Peso, predict(best, df)))
| x |
|---|
| 274.3666 |
Nonostante il piccolo problema di omoschedasticità e i residui che non seguono perfettamente una scala normale, posso sentirmi comunque sicuro sul fatto che il modello non ha problemi nella sua previsione del peso. Infatti, se ora proviamo a fare una previsione considerando una madre con gestazione di 39 settimane 2 gravidanze passate, con il neonato di lunghezza media ed il cranio di misura media e di sesso femminile, riceviamo come previsione dal modello un peso di media 3258.615 grammi.
media_cranio = mean(df$Cranio)
new_data = data.frame(Gestazione = 39, Lunghezza = media_lung, Cranio = media_cranio, N.gravidanze = 2, Sesso = "F")
results = predict.lm(best, newdata = new_data)
kable(results)
| x |
|---|
| 3258.727 |
ggplot(data = df,
aes(x = factor("N. gravidanze"), y = Peso, fill = factor("N. gravidanze")))+
geom_violin()+
geom_boxplot(width = 0.1, outlier.shape = NA, fill = "white", alpha = 0.6)+
labs(
title = "Distribuzione del peso in base al numero di gravidanze",
x = "N. Gravidanze",
y = "Peso in grammi",
fill = "N. Gravidanze"
)+
theme_minimal()
ggplot(data = df)+
geom_boxplot(aes(x = Fumatrici, y = Peso, fill = Sesso))+
labs(
title = "Peso in relazione alla madre fumatrice",
x = "Madre Fumatrice",
y = "Peso in grammi",
fill = "Sesso"
)+
theme_minimal()
ggplot(data = df)+
geom_point(aes(x = Lunghezza,
y = Peso,
col = Sesso), position = "jitter")+
geom_smooth(aes(x = Lunghezza,
y = Peso,
col = Sesso), se = F, method = "lm")+
geom_smooth(aes(x = Lunghezza,
y = Peso), col = "black", se = F, method = "lm")+
theme_minimal()+
labs(
title = "Influenza della Lunghezza sul Peso",
x = "Lunghezza",
y = "Peso",
fill = "Sesso"
)
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
ggplot(data = df)+
geom_point(aes(x = Gestazione,
y = Peso,
col = Sesso), position = "jitter")+
geom_smooth(aes(x = Gestazione,
y = Peso,
col = Sesso), se = F, method = "lm")+
geom_smooth(aes(x = Gestazione,
y = Peso), col = "black", se = F, method = "lm")+
theme_light()
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
Con questi ultimi grafici abbiamo infine un ultima visuale sulle variabili che secondo me possono avere un influenza maggiore sul peso del neonato. Notiamo come la gestazione attorno alle 40 settimane ha un’influenza elevata sul peso ma che comunque nelle “prime” settimane di gestazione questa non influenza troppo il peso, ma nelle settimane più avanti invece il peso riceve molta più influenza, questo perchè il bambino è ora quasi o totalmente formato. Vediamo che le donne fumatrici non hanno una grande influenza sul peso mentre le donne che non fumano si. ed infine vediamo che (come dovremmo aspettarci normalmente), la lunghezza ed il peso sono molto influenti l’una sull’altra.