Data and setup

Save 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)))

Problem 1

1(a) Overall birth-weight distribution and normality

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.

1(b) Birth weight by maternal smoking status

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).

1(c) Normality within each smoking group

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.

Problem 2: Compare birth weights by smoking status

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.

Problem 3: One-way ANOVA

3(a) Check equal variances

# 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\).

3(b) One-way ANOVA and comparison with Problem 2

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.

Problem 4: Block design using infant sex

4(a) Hypotheses for smoking status

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.

  • \(H_0: \mu_S = \mu_N\)
  • \(H_A: \mu_S \ne \mu_N\)

4(b) Explain the block

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.

4(c) Fit the blocked ANOVA model

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.

4(d) Model assumptions and inference

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. )

  1. Normality: The residual Q-Q plot looks pretty straight except for a few points in the tails. Shapiro-Wilk on the residuals gives \(W = 0.99414\) and \(p = 0.3133\), so there’s no significant evidence against normality.
  2. Equal variance: The residuals-vs-fitted and scale-location plots don’t show the spread fanning out. (You only see four vertical stripes because both predictors are 0/1, so there are only four fitted values. That’s expected.) Levene’s test across the four cells gives \(F(3, 291) = 0.430\) and \(p = 0.7315\), and the cell SDs are all around 482–527 g. Equal variance looks reasonable.
  3. Additivity (no interaction): Testing the sex-by-smoking interaction gives \(F(1, 291) = 0.803\) and \(p = 0.3710\). There’s no significant evidence that the smoking difference varies between boys and girls, which supports using the additive model. The smoking cells are small, though, so this check may miss a real interaction.
  4. Independence: We can’t check this from plots. It comes from how the data were collected. These are singleton births, but the file doesn’t tell us if any mom shows up twice or whether births are clustered. Independence remains an assumption.