| Package | Version |
|---|---|
| knitr | 1.51 |
| ggplot2 | 4.0.3 |
| moments | 0.14.1 |
| dplyr | 1.2.1 |
| kableExtra | 1.4.0 |
| tidyr | 1.3.2 |
| broom | 1.0.13 |
| car | 3.1.5 |
Objective: Create a statistical model capable of accurately predicting newborn birth weight, based on clinical variables collected from three hospitals. The project aims to improve the management of high-risk pregnancies, optimize hospital resources, and ensure better neonatal health outcomes.
The project is part of a growing focus on preventing neonatal complications. Predicting newborn birth weight represents a key opportunity to improve clinical planning and reduce the risks associated with problematic births, such as premature births or low birth weight infants. The main benefits this project will bring to the company and the healthcare sector are:
Improved clinical predictions
Optimizing hospital resources
Prevention and identification of risk factors
Evaluation of hospital practices
Supporting Strategic Planning
The table below shows a subset of the data in the dataset:
| Anni.madre | N.gravidanze | Fumatrici | Gestazione | Peso | Lunghezza | Cranio | Tipo.parto | Ospedale | Sesso | |
|---|---|---|---|---|---|---|---|---|---|---|
| 199 | 24 | 0 | 0 | 40 | 3550 | 500 | 348 | Nat | osp2 | M |
| 215 | 29 | 1 | 0 | 38 | 3300 | 500 | 340 | Nat | osp3 | F |
| 802 | 22 | 0 | 0 | 40 | 3150 | 505 | 322 | Ces | osp3 | F |
| 810 | 32 | 0 | 0 | 40 | 3450 | 515 | 344 | Nat | osp3 | M |
| 2118 | 27 | 0 | 0 | 40 | 3370 | 505 | 332 | Nat | osp1 | M |
There are no NA values within the dataset:
## Anni.madre N.gravidanze Fumatrici Gestazione Peso Lunghezza
## 0 0 0 0 0 0
## Cranio Tipo.parto Ospedale Sesso
## 0 0 0 0
The dataset consists of 2,500 observations on 10 variables, that can be described as below:
| Variable | Description | Type |
|---|---|---|
| Mother’s age | Measure of age in years | Quantitative discrete |
| Number of pregnancies | How many pregnancies the mother has had | Quantitative discrete |
| Maternal smoking | A binary indicator (0 = non-smoker, 1 = smoker) | Qualitative nominal |
| Length of pregnancy | Number of weeks of gestation | Quantitative discrete |
| Newborn weight | Newborn’s weight in grams | Quantitative continuous |
| Newborn length | Newborn’s length in centimeters | Quantitative continuous |
| Skull diameter | Newborn’s cranial diameter, which can also be measured during pregnancy via ultrasound | Quantitative continuous |
| Type of birth | Natural or C-section | Qualitative nominal |
| Hospital of birth | Hospital 1, 2, or 3 | Qualitative nominal |
| Newborn’s gender | Male (M) or Female (F) | Qualitative nominal |
| Anni.madre | N.gravidanze | Fumatrici | Gestazione | Peso | Lunghezza | Cranio | Tipo.parto | Ospedale | Sesso | |
|---|---|---|---|---|---|---|---|---|---|---|
| Min. : 0.00 | Min. : 0.0000 | Min. :0.0000 | Min. :25.00 | Min. : 830 | Min. :310.0 | Min. :235 | Length:2500 | Length:2500 | Length:2500 | |
| 1st Qu.:25.00 | 1st Qu.: 0.0000 | 1st Qu.:0.0000 | 1st Qu.:38.00 | 1st Qu.:2990 | 1st Qu.:480.0 | 1st Qu.:330 | Class :character | Class :character | Class :character | |
| Median :28.00 | Median : 1.0000 | Median :0.0000 | Median :39.00 | Median :3300 | Median :500.0 | Median :340 | Mode :character | Mode :character | Mode :character | |
| Mean :28.16 | Mean : 0.9812 | Mean :0.0416 | Mean :38.98 | Mean :3284 | Mean :494.7 | Mean :340 | NA | NA | NA | |
| 3rd Qu.:32.00 | 3rd Qu.: 1.0000 | 3rd Qu.:0.0000 | 3rd Qu.:40.00 | 3rd Qu.:3620 | 3rd Qu.:510.0 | 3rd Qu.:350 | NA | NA | NA | |
| Max. :46.00 | Max. :12.0000 | Max. :1.0000 | Max. :43.00 | Max. :4930 | Max. :565.0 | Max. :390 | NA | NA | NA |
Looking at the table above, you can see an anomaly for the variable Anni.madre, which has a minimum value of 0. We then proceed with checking for outliers to identify those due to measurement or transcription errors within the dataset.
| Anni.madre | N.gravidanze | Fumatrici | Gestazione | Peso | Lunghezza | Cranio | Tipo.parto | Ospedale | Sesso | |
|---|---|---|---|---|---|---|---|---|---|---|
| 138 | 13 | 0 | 0 | 38 | 2760 | 470 | 325 | Nat | osp2 | F |
| 205 | 45 | 2 | 0 | 38 | 3850 | 505 | 384 | Nat | osp3 | M |
| 230 | 43 | 1 | 0 | 35 | 2050 | 455 | 305 | Nat | osp2 | F |
| 260 | 44 | 1 | 0 | 40 | 3500 | 480 | 346 | Nat | osp1 | F |
| 335 | 44 | 0 | 1 | 38 | 3150 | 465 | 335 | Nat | osp3 | F |
| 855 | 43 | 0 | 0 | 38 | 3600 | 510 | 336 | Nat | osp3 | M |
| 1075 | 14 | 1 | 0 | 39 | 3510 | 490 | 365 | Nat | osp2 | M |
| 1106 | 46 | 5 | 0 | 36 | 2710 | 470 | 347 | Nat | osp2 | M |
| 1152 | 1 | 1 | 0 | 41 | 3250 | 490 | 350 | Nat | osp2 | F |
| 1380 | 0 | 0 | 0 | 39 | 3060 | 490 | 330 | Nat | osp3 | M |
| 1532 | 14 | 0 | 0 | 39 | 3550 | 500 | 355 | Ces | osp1 | M |
| 2026 | 44 | 0 | 0 | 40 | 3050 | 505 | 345 | Nat | osp1 | M |
| 2098 | 44 | 5 | 0 | 38 | 3280 | 475 | 346 | Ces | osp1 | F |
The values 1 and 0 for the mothers’ ages (ID 1152 and ID 1380) can be removed as they are biologically impossible and represent obvious data entry errors.
On the contrary, all other identified outliers (adolescent mothers and those older than 43 years) should be considered real values as they are biologically plausible and reflect the variability of the collected data.
# remove wrong values for variable Anni.madre
df <- df %>% filter(Anni.madre >= 13)
summary(df$Anni.madre)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 13.00 25.00 28.00 28.19 32.00 46.00
The table below summarizes each quantitative variable using measures of position (mean, median, quartiles, min and max), dispersion (variance, standard deviation, IQR and CV), and shape (skewness and excess kurtosis).
| Variable | Mean | Median | Q1 | Q3 | Min | Max | Variance | SD | IQR | CV | Skewness | Excess Kurtosis |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Anni.madre | 28.19 | 28 | 25 | 32 | 13 | 46 | 27.22 | 5.22 | 7 | 0.19 | 0.15 | -0.11 |
| N.gravidanze | 0.98 | 1 | 0 | 1 | 0 | 12 | 1.64 | 1.28 | 1 | 1.30 | 2.51 | 10.98 |
| Gestazione | 38.98 | 39 | 38 | 40 | 25 | 43 | 3.49 | 1.87 | 2 | 0.05 | -2.07 | 8.26 |
| Peso | 3284.18 | 3300 | 2990 | 3620 | 830 | 4930 | 275865.90 | 525.23 | 630 | 0.16 | -0.65 | 2.03 |
| Lunghezza | 494.70 | 500 | 480 | 510 | 310 | 565 | 693.21 | 26.33 | 30 | 0.05 | -1.51 | 6.48 |
| Cranio | 340.03 | 340 | 330 | 350 | 235 | 390 | 269.93 | 16.43 | 20 | 0.05 | -0.79 | 2.94 |
Based on density graph below and the above table, we can assume Anni.madre is clearly close to normal distribution with mean ≈ median, skewness ≈ 0.15 and excess kurtosis ≈ −0.11. Variables Peso and Cranio approach a bell shape curve but still skewness.
In order to analyze the remaining qualitative variables related the data frame, it is appropriate to compute frequency distributions.
As shown in the frequency tables below, the distribution of qualitative variables is balanced across the main categories.
Regarding the newborn’s sex, a balanced distribution is observed between the two categories, with percentages of ≈ 49.76% and ≈ 50.24% respectively. The distribution across hospitals is also homogeneous, with each facility contributing approximately one-third of the observations.
| ni | fi | Ni | Fi | |
|---|---|---|---|---|
| F | 1255 | 0.5024 | 1255 | 0.5024 |
| M | 1243 | 0.4976 | 2498 | 1.0000 |
| ni | fi | Ni | Fi | |
|---|---|---|---|---|
| osp1 | 816 | 0.3267 | 816 | 0.3267 |
| osp2 | 848 | 0.3395 | 1664 | 0.6661 |
| osp3 | 834 | 0.3339 | 2498 | 1.0000 |
Regarding the type of birth, a prevalence of vaginal births with ≈ 71% is observed compared to cesarean sections (≈ 29%), consistent with what is generally observed in clinical practice.
| ni | fi | Ni | Fi | |
|---|---|---|---|---|
| Ces | 728 | 0.2914 | 728 | 0.2914 |
| Nat | 1770 | 0.7086 | 2498 | 1.0000 |
Finally, the variable relating to maternal smoking highlights a clear predominance of non-smokers with ≈ 96%, while the share of smokers is ≈ 4%.
| ni | fi | Ni | Fi | |
|---|---|---|---|---|
| 0 | 2394 | 0.9584 | 2394 | 0.9584 |
| 1 | 104 | 0.0416 | 2498 | 1.0000 |
In this section, we will test the following hypotheses with appropriate tests.
The following hypotheses are to be tested:
\[ H_0: \text{The type of delivery is independent of the hospital where it occurs} \] \[ H_1: \text{The type of delivery depends on the hospital where it occurs} \]
res_chi2 <- chisq.test(df$Tipo.parto, df$Ospedale)
print(res_chi2)
##
## Pearson's Chi-squared test
##
## data: df$Tipo.parto and df$Ospedale
## X-squared = 1.083, df = 2, p-value = 0.5819
p-value = 0.5819 is above the 0.05 significance level, by suggesting that the type of delivery is independent of the hospital where it occurs.
Based on data from the World Health Organization Child Growth Standards (https://www.cdc.gov/growthcharts/who-growth-charts.htm) and the Bambin Gesù Hospital in Rome (https://www.ospedalebambinogesu.it/da-0-a-30-giorni-come-si-presenta-e-come-cresce-80012), we can define reference values for average neonatal weight and length to use as a comparison with our data. For this purpose, we used an average weight of 3300 grams and an average length of 500 millimeters.
Let’s proceed with the below hypotheses:
\[ H_0: \mu = 3300 \quad \] \[ H_1: \mu \neq 3300 \quad \]
mu_newborn_weight <- 3300
# Student's test for weight
res_weight <- t.test(df$Peso, mu = mu_newborn_weight, alternative = "two.sided")
print(res_weight)
##
## 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
With a p-value of 0.13, it is possible to state that the mean newborn weight does not differ significantly from the theoretical population mean, therefore the null hypothesis is not rejected.
\[ H_0: \mu = 500 \quad \] \[ H_1: \mu \neq 500 \quad \]
mu_newborn_length <- 500
# Student's test for length
res_length <- t.test(df$Lunghezza, mu = mu_newborn_length, alternative = "two.sided")
print(res_length)
##
## 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
The mean newborn length is significantly shorter than the hypothesized mean of 500 mm (p < 0.001). Therefore, the null hypothesis is rejected.
Let us now analyze the differences between the three anthropometric measurements examined in the dataset (newborn weight, length and diameter of the skull) between the two sexes using the Student test for independent groups:
\[ H_0: \mu_M = \mu_F \quad \] \[ H_1: \mu_M \neq \mu_F \quad \]
##
## Welch Two Sample t-test
##
## data: df$Peso by Sesso
## t = -12.115, df = 2488.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.4841 -207.3844
## sample estimates:
## mean in group F mean in group M
## 3161.061 3408.496
##
## Welch Two Sample t-test
##
## data: df$Lunghezza by Sesso
## t = -9.5823, df = 2457.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.939001 -7.882672
## sample estimates:
## mean in group F mean in group M
## 489.7641 499.6750
##
## Welch Two Sample t-test
##
## data: df$Cranio by 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
The results of the tests reported above lead us to the conclusion that the anthropometric measurements considered are significantly different between the two sexes.
Specifically:
the mean weight is ≈ 3161 g for females and 3408 g for males, with a p-value < 2.2e-16.
the mean length is ≈ 500 mm for males and ≈ 490 mm for females, with a p-value < 2.2e-16
the mean skull diameter is ≈ 338 mm for males and ≈ 342 mm for females, with a p-value = 1.414e-13
Therefore, the null hypothesis is rejected.
A multiple linear regression model will be developed that includes all relevant variables. This will allow us to quantify the impact of each independent variable on newborn weight and any interactions. For example, we expect that a longer gestation period would increase newborn weight on average.
Let’s check that the model’s response variable (newborn weight) is approximately normal, considering the shape indices, as per section 2.1.1, and performing the Shapiro-Wilk normality test:
| Variable | Skewness | Excess Kurtosis |
|---|---|---|
| Peso | -0.65 | 2.03 |
##
## Shapiro-Wilk normality test
##
## data: df$Peso
## W = 0.97068, p-value < 2.2e-16
With a p-value < 2.2e-16, the test leads us to reject the null hypothesis, so the weight variable does not appear to follow a Normal distribution.
However, given the large sample size, the test becomes sensitive even to small deviations from the Normal distribution.
Therefore, by combining a visual analysis with a histogram graph, it is possible to assert that the weight variable tends to follow a Normal distribution that is moderately left-skewed and leptokurtic.
We use the correlation matrix tool to assess the linear relationship between the numerical variables in the dataset (thus excluding categorical variables) according to the Pearson correlation coefficient.
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)
}
# consider only quantitative variables to be used for the correlation analysis
df_numeric <- df %>% select(all_of(vars_quantitative))
pairs(df_numeric, upper.panel = panel.smooth, lower.panel = panel.cor)
The analysis shows that newborn weight is correlated with both length and skull diameter, suggesting that longer newborns with broader skulls tend to have higher weight. Furthermore, gestational length also shows a positive correlation with weight, indicating that a greater number of weeks of gestation is associated with a slight increase in birth weight.
We define the first model by excluding the variables “Type of birth” and “Hospital” which have no direct predictive value with respect to the newborn’s weight:
mod1 <- lm(Peso ~ .-Tipo.parto -Ospedale, data = df)
summary (mod1)
##
## Call:
## lm(formula = Peso ~ . - Tipo.parto - Ospedale, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1160.6 -181.3 -15.7 163.6 2630.7
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6712.2405 141.3339 -47.492 < 2e-16 ***
## Anni.madre 0.8803 1.1491 0.766 0.444
## N.gravidanze 11.3789 4.6767 2.433 0.015 *
## Fumatrici -30.3958 27.6080 -1.101 0.271
## Gestazione 32.9472 3.8288 8.605 < 2e-16 ***
## Lunghezza 10.2316 0.3011 33.979 < 2e-16 ***
## Cranio 10.5198 0.4271 24.633 < 2e-16 ***
## SessoM 78.0787 11.2132 6.963 4.24e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 274.7 on 2490 degrees of freedom
## Multiple R-squared: 0.7272, Adjusted R-squared: 0.7264
## F-statistic: 948.3 on 7 and 2490 DF, p-value: < 2.2e-16
The F-statistic = 948.30, with a p-value < 2.2e-16, confirms that the overall model is highly significant. The value of Adjusted R² = 0.7264 indicates that a large part of the variance of the dependent variable “newborn weight” is explained by the independent variables of the model.
From the model summary, the following variables are statistically relevant, showing a significant linear relationship with newborn’s weight:
The number of previous pregnancies also appears to have some influence, but much less so than the other variables listed above.
# check for multicollinearity
vif(mod1)
## Anni.madre N.gravidanze Fumatrici Gestazione Lunghezza Cranio
## 1.189264 1.187447 1.006692 1.694331 2.079749 1.628987
## Sesso
## 1.040493
The VIF values are below the threshold of 5, indicating there are no multicollinearity effects.
We define a second model by removing the variables “mother’s age” and “maternal smoking” which in the previous analysis showed very high p-values, therefore indicating that they do not have a significant impact on the newborn’s weight.
mod2 <- update(mod1, ~ .-Anni.madre -Fumatrici)
summary (mod2)
##
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio +
## 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 ***
## N.gravidanze 12.4554 4.3416 2.869 0.00415 **
## 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 ***
## 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
The F-statistic = 1327, with a p-value < 2.2e-16, confirms that also this 2nd model is highly significant. The value of Adjusted R² = 0.7265 is substantially unchanged compared to the first model.
# check for multicollinearity
vif(mod2)
## N.gravidanze Gestazione Lunghezza Cranio Sesso
## 1.023462 1.669779 2.075747 1.624568 1.040184
Also for this 2nd model, the VIF values are below the threshold of 5, indicating there are no multicollinearity effects.
We proceed with further evaluations by performing the ANOVA (analysis of variance), AIC (akaike information criterion) and BIC (bayesian information criterion) tests:
anova(mod2, mod1)
## Analysis of Variance Table
##
## Model 1: Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso
## Model 2: Peso ~ (Anni.madre + N.gravidanze + Fumatrici + Gestazione +
## Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso) - Tipo.parto -
## Ospedale
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 2492 188042054
## 2 2490 187905214 2 136840 0.9067 0.404
AIC(mod2, mod1)
## df AIC
## mod2 7 35152.89
## mod1 9 35155.07
BIC(mod2, mod1)
## df BIC
## mod2 7 35193.65
## mod1 9 35207.48
The ANOVA test reports a p-value = 0.404, confirming what was deduced from the comparison between the Adjusted R²: the difference between the two models is not statistically significant and the simplification does not involve a substantial loss of information.
Even in the comparison between the AIC and BIC tests, the lower values for mod2 suggest a preference for the simpler one.
As a result of above tests, we can conclude that mod2 does not imply a loss of prediction compared to mod1, despite being a simplified model. Therefore, mod2 appears to be the preferred model.
In this section, we will perform a residual analysis of the chosen regression model (mod2) by studying the differences between the observed and predicted values to verify whether the basic statistical assumptions are met.
We will use graphs to understand the behavior of the residuals:
par(mfrow=c(2,2))
plot(mod2)
Residuals vs. Fitted and Scale-Location: a tendency for the residuals and standardized residuals, to become more dispersed with increasing weight values is observed, with a slight curvature, which could indicate potential heteroskedasticity. Additionally, some extreme points are also present.
Q-Q residuals: the residuals are arranged along the bisector of the graph, with some deviations in the tails. Combined with the result of the Shapiro-Wilk test below and the density graph, we can assume a slight deviation from perfect normality of the residuals due to the large dataset size.
# check the Normality assumption for the model residuals
shapiro.test(residuals(mod2))
##
## Shapiro-Wilk normality test
##
## data: residuals(mod2)
## W = 0.97414, p-value < 2.2e-16
plot(density(residuals(mod2)))
- Residuals vs. Leverage: there are some observations
that show high leverage values based on their Cook’s distance
values. In particular the value for the observation
#1549 is between the warning and alarm thresholds.These
could represent residuals of influential observations.
Let’s proceed by using numerical methods to further investigate leverage values and outliers.
We can check which observations tend to be distant from the others in the regressor space, so those observations with leverage values higher than the threshold value:
\[ \text{threshold value} = \frac{2p}{n} \] where:
# function definition for leverage
leverage.for.model <- function(mod, print_values = TRUE){
lev <- hatvalues(mod)
plot(lev)
# definition for threshold value used to classify values as leverage or not
p <- sum(lev)
n <- length(lev)
threshold.value = 2*p/n
abline(h=threshold.value, col=2)
if(print_values){
# print leverage values above the threshold
lev[lev>threshold.value]
}
}
leverage.for.model(mod2)
## 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 956 985 1008 1014 1049
## 0.008409518 0.007791530 0.007040035 0.005343994 0.008474086 0.004956561
## 1067 1091 1106 1130 1165 1180
## 0.008467035 0.008940030 0.005967511 0.031739177 0.005513581 0.005678043
## 1187 1199 1218 1237 1247 1272
## 0.006481533 0.005493009 0.030697778 0.005912496 0.014631359 0.007089553
## 1290 1292 1310 1320 1324 1355
## 0.006118589 0.006074423 0.009626391 0.009295311 0.004857340 0.005306940
## 1356 1383 1393 1398 1400 1409
## 0.006967713 0.012641828 0.005129491 0.005932524 0.004816704 0.008049539
## 1418 1426 1427 1448 1503 1549
## 0.005156670 0.008195421 0.021758961 0.015106684 0.013334256 0.048802841
## 1551 1554 1571 1591 1604 1608
## 0.008507417 0.005923458 0.005049368 0.005624961 0.005009312 0.008725821
## 1615 1617 1626 1684 1691 1699
## 0.004869997 0.015069038 0.005070717 0.009356578 0.005079185 0.010846383
## 1710 1716 1725 1733 1778 1779
## 0.006993461 0.006961226 0.013303625 0.004886226 0.025544997 0.016833696
## 1807 1825 1866 1890 1960 1965
## 0.008711082 0.006068655 0.005206137 0.005333985 0.005541287 0.005339716
## 1975 2035 2038 2044 2084 2087
## 0.006928794 0.004890003 0.011504028 0.005471894 0.013194769 0.006293791
## 2096 2112 2113 2118 2138 2144
## 0.005097113 0.013318873 0.011779730 0.018667270 0.006244737 0.005804705
## 2146 2147 2155 2173 2198 2213
## 0.007930323 0.013589469 0.005910248 0.032531736 0.011679031 0.004894044
## 2214 2218 2219 2222 2223 2242
## 0.008120291 0.005415586 0.021633907 0.005841119 0.005593576 0.006929530
## 2255 2305 2315 2316 2335 2357
## 0.006171101 0.013972901 0.007677230 0.004834368 0.005230839 0.010068259
## 2406 2420 2434 2435 2450 2456
## 0.009702475 0.021536269 0.004986609 0.023951342 0.023848222 0.008509142
## 2469 2476
## 0.020905930 0.005777111
In a similar way, we can proceed to identify the outliers, that is, those extreme values of the response variable.
This procedure involves using the rstudent function on the regression model to build another scatter-plot graph, with horizontal thresholds representing the number of standard deviations away from the regression line:
# outliers for lm function definition
outliers.for.model <- function(model, print_values = FALSE, columns = NULL){
resz.model <- rstudent(model)
plot(resz.model)
# 95% of data between ±2 sd
abline(h=c(-2,2), col="red")
# 99.7% of data between ±3 sd
abline(h=c(-3,3), col="blue")
if(print_values == TRUE && is.null(columns) == FALSE)
print(df[which(abs(resz.model) > 3), columns])
}
outliers.for.model(mod2, TRUE, all.vars.mod2)
## Peso N.gravidanze Gestazione Lunghezza Cranio Sesso
## 119 3410 0 40 550 372 M
## 130 4240 2 39 485 352 M
## 155 3610 0 36 410 330 M
## 310 1560 3 28 420 379 F
## 791 4440 1 41 510 335 M
## 1036 4330 0 40 500 355 F
## 1267 3790 1 40 460 332 F
## 1292 4600 3 38 485 380 M
## 1305 4900 0 41 510 352 F
## 1397 2560 2 38 525 349 M
## 1539 4540 0 38 530 343 M
## 1549 4370 1 38 315 374 F
## 1551 4520 4 35 520 360 F
## 1633 3430 2 39 445 322 F
## 1692 3850 1 36 460 334 F
## 1918 4930 0 39 550 350 F
## 2021 4650 1 39 510 354 M
## 2113 1890 1 32 500 309 F
## 2193 3980 1 40 480 335 F
## 2217 2500 1 39 490 352 M
## 2223 3140 0 35 465 290 F
## 2313 2800 0 42 520 340 M
The point cloud appears to be distributed homogeneously around zero, suggesting homoscedasticity. However, several points exceed the |3| threshold, confirming the presence of isolated outliers.
Given the sample size considered, we perform the formal Bonferroni test to correct for multiple testing bias, that identify #3 statistically significant outliers with Bonferroni p-value << 0.05:
res.outlierTest.mod2 <- outlierTest(mod2)
res.outlierTest.mod2
## rstudent unadjusted p-value Bonferroni p
## 1549 10.046230 2.6345e-23 6.5810e-20
## 155 5.025345 5.3818e-07 1.3444e-03
## 1305 4.824963 1.4848e-06 3.7092e-03
df[as.numeric(names(res.outlierTest.mod2$rstudent)), all.vars.mod2]
## Peso N.gravidanze Gestazione Lunghezza Cranio Sesso
## 1549 4370 1 38 315 374 F
## 155 3610 0 36 410 330 M
## 1305 4900 0 41 510 352 F
Let’s continue analyzing the model using Cook’s distance, which indicates how much the entire regression model would change if a single point were removed. A high Cook’s distance implies that the specific observation has a significant and potentially critical impact on the coefficients of the linear regression model.
# cook's distance with graph function definition
cooks.distance.graph <- function(lm){
cook <- cooks.distance(lm)
plot(cook, ylim = c(0,1))
# print index value for top 3 observations
# based on cook's distances
top3.cook.indices <- order(cook, decreasing = TRUE)[1:3]
text(x = top3.cook.indices, y = cook[top3.cook.indices],
labels = top3.cook.indices, col = "red", pos = 3)
text(x = top3.cook.indices, y = cook[top3.cook.indices],
labels = round(cook[top3.cook.indices],4), col = "blue", pos = 4, cex = 0.6)
}
cooks.distance.graph(mod2)
Based on the tests performed, particular attention is paid to
observation 1549:
These tests reveal a data entry error, and this is confirmed by observing the data for #1549:
## Peso N.gravidanze Gestazione Lunghezza Cranio Sesso
## 1549 4370 1 38 315 374 F
The weight = 4370g is typical of newborns of advanced gestational age but biologically possible at 38 weeks of gestation. However, it is not compatible with a length = 315 mm, which is even smaller than the skull diameter (374 mm).
Since it is not possible to correct this error, we proceed with removing the data, redefining the regression model and analyzing the residuals.
We define a second version for the mod2 by removing the outlier identified in the previous paragraph from data:
df_2.1 <- df[rownames(df) != "1549",]
mod2.1 <- lm(Peso ~ .-Tipo.parto -Ospedale -Anni.madre -Fumatrici, data = df_2.1)
summary (mod2.1)
##
## Call:
## lm(formula = Peso ~ . - Tipo.parto - Ospedale - Anni.madre -
## Fumatrici, data = df_2.1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1165.68 -179.74 -12.42 162.92 1410.68
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -6683.8326 133.1602 -50.194 < 2e-16 ***
## N.gravidanze 13.1448 4.2576 3.087 0.00204 **
## Gestazione 29.6341 3.7369 7.930 3.27e-15 ***
## Lunghezza 10.8899 0.3019 36.077 < 2e-16 ***
## Cranio 9.9192 0.4227 23.465 < 2e-16 ***
## SessoM 78.1376 10.9929 7.108 1.53e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 269.3 on 2491 degrees of freedom
## Multiple R-squared: 0.7372, Adjusted R-squared: 0.7367
## F-statistic: 1398 on 5 and 2491 DF, p-value: < 2.2e-16
The F-statistic = 1398, with a p-value < 2.2e-16, confirms that also the mod2.1 is highly significant. With the removal of observation 1549, there was an improvement with the adjusted R² increased from 0.7264 to 0.7367
We can now proceed with the residual analysis for the regression model mod2.1, as in section #2.4:
par(mfrow=c(2,2))
plot(mod2.1)
# check the Normality assumption for the model residuals
shapiro.test(residuals(mod2.1))
##
## Shapiro-Wilk normality test
##
## data: residuals(mod2.1)
## W = 0.98891, p-value = 5.23e-13
leverage.for.model(mod2.1, FALSE)
outliers.for.model(mod2.1, FALSE)
res.outlierTest.mod2.1 <- outlierTest(mod2.1)
res.outlierTest.mod2.1
## rstudent unadjusted p-value Bonferroni p
## 155 5.285313 1.3639e-07 0.00034056
## 1305 4.940535 8.3077e-07 0.00207440
## 1397 -4.348609 1.4251e-05 0.03558600
df[as.numeric(names(res.outlierTest.mod2.1$rstudent)), all.vars.mod2]
## Peso N.gravidanze Gestazione Lunghezza Cranio Sesso
## 155 3610 0 36 410 330 M
## 1305 4900 0 41 510 352 F
## 1397 2560 2 38 525 349 M
cooks.distance.graph(mod2.1)
Removing outlier #1549 appears to have slightly improved the fit of the regression model. However, as highlighted by the Residuals Q-Q plot, as for mod2, the residuals show some deviations in the tails. This, combined with the Shapiro-Wilk test result (W = 0.98891, p-value = 5.23e-13), leads us to confirm a slight deviation from perfect normality of the residuals due to the large sample size.
Then, it’s possible to consider a non-linear relationship between the features.
We then update the model, by adding a quadratic (non-linear) relationship with the variables for length of pregnancy and newborn’s length:
mod2.2 <- update(mod2.1, ~. + I(Gestazione^2) + I(Lunghezza^2))
summary(mod2.2)
##
## Call:
## lm(formula = Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio +
## Sesso + I(Gestazione^2) + I(Lunghezza^2), data = df_2.1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1187.6 -180.9 -12.4 164.2 1319.9
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.811e+03 9.024e+02 -3.115 0.001860 **
## N.gravidanze 1.438e+01 4.219e+00 3.408 0.000664 ***
## Gestazione 2.000e+02 6.621e+01 3.020 0.002552 **
## Lunghezza -1.925e+01 4.537e+00 -4.244 2.28e-05 ***
## Cranio 1.010e+01 4.204e-01 24.011 < 2e-16 ***
## SessoM 7.339e+01 1.093e+01 6.715 2.32e-11 ***
## I(Gestazione^2) -2.130e+00 8.678e-01 -2.454 0.014198 *
## I(Lunghezza^2) 3.090e-02 4.621e-03 6.687 2.80e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 266.7 on 2489 degrees of freedom
## Multiple R-squared: 0.7426, Adjusted R-squared: 0.7419
## F-statistic: 1026 on 7 and 2489 DF, p-value: < 2.2e-16
The coefficients I(Gestazione^2) (p-value ≈ 0.0142) and I(Lunghezza^2) (p-value ≈ 0) pass the significance tests. The Adjusted R² increase from 0.7367 to 0.7419. This means that the quadratic model explains approximately 0.52% more of the total variability for newborn’s weight (≈ 74.19%).
anova(mod2.2, mod2.1)
## Analysis of Variance Table
##
## Model 1: Peso ~ N.gravidanze + Gestazione + Lunghezza + Cranio + Sesso +
## I(Gestazione^2) + I(Lunghezza^2)
## Model 2: Peso ~ (Anni.madre + N.gravidanze + Fumatrici + Gestazione +
## Lunghezza + Cranio + Tipo.parto + Ospedale + Sesso) - Tipo.parto -
## Ospedale - Anni.madre - Fumatrici
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 2489 177006781
## 2 2491 180719906 -2 -3713125 26.106 6.018e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
AIC(mod2.2, mod2.1)
## df AIC
## mod2.2 9 34992.81
## mod2.1 7 35040.64
BIC(mod2.2, mod2.1)
## df BIC
## mod2.2 9 35045.21
## mod2.1 7 35081.40
The BIC value for mod2.2 (35045.21) is slightly lower than BIC for mod2.1 (35081.40).
par(mfrow=c(2,2))
plot(mod2.2)
# check the Normality assumption for the model residuals
shapiro.test(residuals(mod2.2))
##
## Shapiro-Wilk normality test
##
## data: residuals(mod2.2)
## W = 0.99048, p-value = 8.393e-12
plot(density(residuals(mod2.2)))
As for the results discussed in section #2.4, also for mod2.2, the density graph combined with the result of the Shapiro-Wilk (W = 0.99048, p-value = 8.393e-12), show some deviations in the tails and a not perfect normality of the residuals.
# studentized Breusch-Pagan test
lmtest::bptest(mod2.2)
##
## studentized Breusch-Pagan test
##
## data: mod2.2
## BP = 17.125, df = 7, p-value = 0.01661
# Durbin-Watson test
lmtest::dwtest(mod2.2)
##
## Durbin-Watson test
##
## data: mod2.2
## DW = 1.9496, p-value = 0.104
## alternative hypothesis: true autocorrelation is greater than 0
Also, the graphs Residuals vs fitted, Scale-location and the Breusch-Pagan test (BP = 17.125, p-value = 0.01661), confirm a potential heteroskedasticity.
The result of the Durbin-Watson test on model mod2.2 (DW = 1.9496, p-value = 0.104) indicates that the residuals are not autocorrelated.
leverage.for.model(mod2.2, FALSE)
outliers.for.model(mod2.2, FALSE)
res.outlierTest.mod2.2 <- outlierTest(mod2.2)
res.outlierTest.mod2.2
## rstudent unadjusted p-value Bonferroni p
## 1305 4.978664 6.8407e-07 0.0017081
## 155 4.845078 1.3434e-06 0.0033545
## 1397 -4.476653 7.9239e-06 0.0197860
## 1692 4.344872 1.4495e-05 0.0361940
df[as.numeric(names(res.outlierTest.mod2.2$rstudent)), all.vars.mod2]
## Peso N.gravidanze Gestazione Lunghezza Cranio Sesso
## 1305 4900 0 41 510 352 F
## 155 3610 0 36 410 330 M
## 1397 2560 2 38 525 349 M
## 1692 3850 1 36 460 334 F
cooks.distance.graph(mod2.2)
While the previous conclusions on the outliers and leverage charts remain valid, it was shown that outlier #1549 acted as a real distorting factor.
Mod2.2 is therefore better than mod2.1.
Once the model has been validated, we will use it to make practical predictions. For example, we could estimate the weight of a newborn girl, considering a mother in her third pregnancy who is due to give birth at 39 weeks.
row <- data.frame(
N.gravidanze = 3,
Gestazione = 39,
Lunghezza = quantitative_vars_table_results[quantitative_vars_table_results$Variable == 'Lunghezza', 'Mean'],
Cranio = quantitative_vars_table_results[quantitative_vars_table_results$Variable == 'Cranio', 'Mean'],
Sesso = "F"
)
prediction.mod2.2 <- predict(mod2.2, newdata = row, interval = "confidence", level = 0.95)
# print as table with columns for prediction renamed
table.prediction.mod2.2 <- cbind(row, prediction.mod2.2)
names(table.prediction.mod2.2)[(ncol(table.prediction.mod2.2) - 2):ncol(table.prediction.mod2.2)] <- c("Fit", "CI.lower", "CI.upper")
kable(table.prediction.mod2.2,
caption = "Prediction with mod2.2 at 95% CI",
align = "lllllrrr",
digits = 2,
booktabs = TRUE)
| N.gravidanze | Gestazione | Lunghezza | Cranio | Sesso | Fit | CI.lower | CI.upper |
|---|---|---|---|---|---|---|---|
| 3 | 39 | 494.7 | 340.03 | F | 3262.66 | 3239.74 | 3285.58 |
In this section, graphs will be used to show the impact of the number of weeks of gestation and smoking on the predicted weight.
# df_2.1 is the original dataframe with the
# exclusion of outlier #1549
ggplot(data = df_2.1) +
geom_point(aes(x = Gestazione,
y = Peso,
col = factor(Fumatrici)), position = "jitter") +
geom_smooth(aes(x = Gestazione,
y = Peso,
col = factor(Fumatrici)), se = FALSE, method = "lm", formula = y ~ x) +
geom_smooth(aes(x = Gestazione,
y = Peso), col="black", se = FALSE, method = "lm", formula = y ~ x) +
labs(title = "Impact of the number of weeks of gestation and smoking on the predicted weight",
x = "Pregnancy length (weeks)",
y = "Newborn's weight (g)",
color = "Maternal smoking") +
scale_color_manual(values = c("skyblue", "orange"),
labels = c("False", "True")) +
theme_minimal()
As with the summary for mod1 in Section 2.3.3, the graph above indicates that the maternal smoking feature has little influence on the newborn’s weight. Indeed, it can be observed that the black line, that represents the relationship between the newborn’s weight with the length of gestation, appears to coincide (save for a very slight difference in slope) with the sky blue line (Maternal smoking = False).
Scope of this study was to implement a linear regression model capable of predicting a newborn’s weight based on anthropometric characteristics.
Model mod2.2 explains 74.19% of the total variability in newborn weight by using only five predictors (two of which involve a quadratic relationship), demonstrating excellent predictive capability.
The Shapiro-Wilk test rejected perfect normality of the residuals, however on large datasets this test is overcritical. According to the Central Limit Theorem, as sample size increases, regression coefficient estimates tend to follow a normal distribution, even if the residuals are not normally distributed.
However, regarding the presence of heteroscedasticity, the linear regression model could be replaced by a Generalized Linear Model (GLM), capable to better fitting the data and handling distributions other than the Normal distribution.