October 20, 2026Save birthweight.csv in the same folder as this
.Rmd file before knitting.
# Install once if needed:
# install.packages(c("ggplot2", "car"))
library(ggplot2)
library(car)
bw <- read.csv("birthweight.csv")
# Check that the expected columns exist and inspect the data.
names(bw)
## [1] "Weight" "Black" "Married" "Boy" "MomSmoke" "Ed"
str(bw)
## 'data.frame': 295 obs. of 6 variables:
## $ Weight : int 2891 3572 3827 4593 3940 2778 3544 3402 3147 3997 ...
## $ Black : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Married : int 1 1 1 1 0 1 1 1 0 1 ...
## $ Boy : int 0 1 0 1 1 0 1 0 0 1 ...
## $ MomSmoke: int 0 0 0 0 1 0 0 0 0 0 ...
## $ Ed : int 1 0 1 1 1 1 1 1 0 1 ...
summary(bw)
## Weight Black Married Boy
## Min. :1526 Min. :0.0000 Min. :0.000 Min. :0.0000
## 1st Qu.:3033 1st Qu.:0.0000 1st Qu.:0.000 1st Qu.:0.0000
## Median :3370 Median :0.0000 Median :1.000 Median :1.0000
## Mean :3387 Mean :0.1661 Mean :0.722 Mean :0.5254
## 3rd Qu.:3742 3rd Qu.:0.0000 3rd Qu.:1.000 3rd Qu.:1.0000
## Max. :4848 Max. :1.0000 Max. :1.000 Max. :1.0000
## MomSmoke Ed
## Min. :0.000 Min. :0.0000
## 1st Qu.:0.000 1st Qu.:0.0000
## Median :0.000 Median :0.0000
## Mean :0.139 Mean :0.4475
## 3rd Qu.:0.000 3rd Qu.:1.0000
## Max. :1.000 Max. :1.0000
# Treat the binary indicators as factors for grouped analyses.
bw$MomSmoke <- factor(bw$MomSmoke, levels = c(0, 1),
labels = c("Non-smoking", "Smoking"))
bw$Boy <- factor(bw$Boy, levels = c(0, 1),
labels = c("Girl", "Boy"))
stopifnot(all(c("Weight", "MomSmoke", "Boy") %in% names(bw)))
boxplot(bw$Weight,
main = "Infant birth weight",
ylab = "Birth weight (grams)",
col = "lightblue")
qqnorm(bw$Weight, main = "Normal Q-Q plot: birth weight")
qqline(bw$Weight, col = "red", lwd = 2)
shapiro.test(bw$Weight)
##
## Shapiro-Wilk normality test
##
## data: bw$Weight
## W = 0.99206, p-value = 0.1153
Some conclusions: The boxplot indicates that the median birth weight is approximately 3,400 grams, with the middle 50% of values (the interquartile range) spanning roughly from 3,000 g to 3,750 g. The whiskers show that most typical birth weights lie between approximately 2,250 g and 4,600 g. Additionally, the boxplot reveals several low birth weight outliers falling below 2,000 grams (specifically near 1,500 g, 1,700 g, and 1,900 g) as well as a single high outlier near 4,800 grams.
The Normal Q-Q plot demonstrates that the central body of the data follows an approximately normal distribution, as the majority of sample points closely track along the red reference line between theoretical quantiles of -1.5 and 1.5. However, at the lower theoretical quantiles (below -2.0), the data points deviate by dropping below the reference line. This confirms a heavy lower tail, driven by the low birth weight outliers identified in the boxplot.
The Shapiro-Wilk normality test provides a p-value of 0.1153, which is greater than \(\alpha\) = 0.05. We thus fail to reject the null hypothesis that the birth weight comes from a normal distribution.
boxplot(Weight ~ MomSmoke, data = bw,
xlab = "Maternal smoking status",
ylab = "Birth weight (grams)",
main = "Birth weight by maternal smoking status",
col = c("lightgreen", "lightpink"))
# Numerical summaries to support the plot-based comparison
aggregate(Weight ~ MomSmoke, data = bw,
FUN = function(x) c(n = length(x),
mean = mean(x),
sd = sd(x),
median = median(x),
IQR = IQR(x)))
## MomSmoke Weight.n Weight.mean Weight.sd Weight.median Weight.IQR
## 1 Non-smoking 254.0000 3422.7244 505.5865 3402.0000 702.0000
## 2 Smoking 41.0000 3162.7073 486.8267 3090.0000 539.0000
Conclusions: Boxplot of weight by MomSmoke=0 and 1. Seems to have larger values in MomSmoke=0 (non-smoking mom).
by(bw$Weight, bw$MomSmoke, shapiro.test)
## bw$MomSmoke: Non-smoking
##
## Shapiro-Wilk normality test
##
## data: dd[x, ]
## W = 0.99362, p-value = 0.3549
##
## ------------------------------------------------------------
## bw$MomSmoke: Smoking
##
## Shapiro-Wilk normality test
##
## data: dd[x, ]
## W = 0.96299, p-value = 0.2
Conclusions: For each level of MomSmoke, normality assumption looks valid. Both follow noramal, as both p-values from tapiro-Wilk normality test are larger than \(\alpha\) = 0.05.
Let \(\mu_S\) be the population mean birth weight for infants of smoking mothers and \(\mu_N\) the population mean for infants of non-smoking mothers.
Pre-check: Both follow normal distribution. So we go ahead 2-sample t-test. Check equal variance assumption and we can conclude that equal variance assumption holds. We check Pooled test result and its p-value is .0023. We make a conclusion that there is significant difference between infant weights between smoking and non-smoking moms.
Equal variance test result
var.test(Weight ~ MomSmoke, data=bw)
##
## F test to compare two variances
##
## data: Weight by MomSmoke
## F = 1.0786, num df = 253, denom df = 40, p-value = 0.8009
## alternative hypothesis: true ratio of variances is not equal to 1
## 95 percent confidence interval:
## 0.6421109 1.6671729
## sample estimates:
## ratio of variances
## 1.078555
# Run the two-sample t-test with equal variance:
t.test(Weight ~ MomSmoke, data = bw, var.equal = TRUE,
alternative = "two.sided", conf.level = 0.95)
##
## Two Sample t-test
##
## data: Weight by MomSmoke
## t = 3.071, df = 293, p-value = 0.002334
## alternative hypothesis: true difference in means between group Non-smoking and group Smoking is not equal to 0
## 95 percent confidence interval:
## 93.37931 426.65488
## sample estimates:
## mean in group Non-smoking mean in group Smoking
## 3422.724 3162.707
Conclusions: The p-value from the two-sample t-test with equal variance is 0.002334, which is smaller than \(\alpha\)=0.05. We thus reject the null hypothesis and conclude that the data provide sufficient evidence that the means of the two groups are statistically different.
# Visual check
plot(Weight ~ MomSmoke, data = bw,
xlab = "Maternal smoking status",
ylab = "Birth weight (grams)",
main = "Birth weight by smoking status")
# Levene's test (median-centered; robust to non-normality)
leveneTest(Weight ~ MomSmoke, data = bw, center = median)
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 1 0.6767 0.4114
## 293
# Group standard deviations as a descriptive check
aggregate(Weight ~ MomSmoke, data = bw, FUN = sd)
## MomSmoke Weight
## 1 Non-smoking 505.5865
## 2 Smoking 486.8267
Conclusions: Levene’s test tells that the equal variance assumption holds as p-value of 0.4114 is larger than \(\alpha=0.05\).
fit_aov <- aov(Weight ~ MomSmoke, data = bw)
summary(fit_aov)
## Df Sum Sq Mean Sq F value Pr(>F)
## MomSmoke 1 2386708 2386708 9.431 0.00233 **
## Residuals 293 74151291 253076
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Diagnostic plots for the fitted ANOVA
par(mfrow = c(2, 2))
plot(fit_aov)
par(mfrow = c(1, 1))
# Normality of model residuals
shapiro.test(residuals(fit_aov))
##
## Shapiro-Wilk normality test
##
## data: residuals(fit_aov)
## W = 0.99375, p-value = 0.2624
Conclusions: The p-value of 0.00233 is larger than \(\alpha=0.05\), so we reject the null hypothesis and conclude that at least one group mean of infant Weights differs between smoking and non-smoking moms.
Let \(\mu_S\) be the population mean birth weight for infants of smoking mothers and \(\mu_N\) the population mean for infants of non-smoking mothers.
Explain in your own words why infant sex (Boy) is
included as a blocking factor. For instance, it accounts for potential
birth-weight variation between girls and boys while estimating the
smoking-status effect. In this additive model, the block is included as
a factor; no smoking-by-sex interaction is included unless the study
question or model is explicitly expanded to allow one.
fit_block <- aov(Weight ~ MomSmoke + Boy, data = bw)
summary(fit_block)
## Df Sum Sq Mean Sq F value Pr(>F)
## MomSmoke 1 2386708 2386708 9.421 0.00235 **
## Boy 1 172899 172899 0.682 0.40942
## Residuals 292 73978392 253351
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
This model treats maternal smoking status as the effect of interest and infant sex as the block. The-value of the ANOVA test is 0.00235 less than \(\alpha\)=0.05. We thus reject the null hypothesis and conclude that at least one group mean of infant Weights differs between smoking and non-smoking moms.
par(mfrow = c(2, 2))
plot(fit_block)
par(mfrow = c(1, 1))
# Residual normality diagnostic
shapiro.test(residuals(fit_block))
##
## Shapiro-Wilk normality test
##
## data: residuals(fit_block)
## W = 0.99414, p-value = 0.3133
# Check whether residual spread differs across smoking groups
leveneTest(residuals(fit_block) ~ bw$MomSmoke, center = median)
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 1 0.6476 0.4216
## 293
# Extract the smoking-status ANOVA row for convenient reporting
summary_block <- summary(fit_block)[[1]]
summary_block
## Df Sum Sq Mean Sq F value Pr(>F)
## MomSmoke 1 2386708 2386708 9.4206 0.002347 **
## Boy 1 172899 172899 0.6824 0.409419
## Residuals 292 73978392 253351
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Conclusions: (The following conclusions are chosen from a student’s solution of this class. Thanks for his great work. )