How to use this document. Run the code along with me. Comments start with
#. This additional-practice script uses theCollegeDistancedataset and mirrors the structure of the PS4 P3 (Olken experiment) analysis.
Today’s plan
CollegeDistance datarm(list = ls()) # clean environment
# Load the required packages
library(AER)
library(ggplot2)
library(dplyr)In the live session we set the working directory with
setwd(...). Here theCollegeDistancedata ships inside theAERpackage, so no working directory or external file is needed.
# Load CollegeDistance dataset from the AER package
data("CollegeDistance")
college <- CollegeDistance
remove(CollegeDistance) # two identical copies load; keep one
# Inspect the dataset
str(college)#> 'data.frame': 4739 obs. of 14 variables:
#> $ gender : Factor w/ 2 levels "male","female": 1 2 1 1 2 1 2 2 1 2 ...
#> $ ethnicity: Factor w/ 3 levels "other","afam",..: 1 1 1 2 1 1 1 1 1 1 ...
#> $ score : num 39.2 48.9 48.7 40.4 40.5 ...
#> $ fcollege : Factor w/ 2 levels "no","yes": 2 1 1 1 1 1 1 1 2 1 ...
#> $ mcollege : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
#> $ home : Factor w/ 2 levels "no","yes": 2 2 2 2 1 2 2 2 2 2 ...
#> $ urban : Factor w/ 2 levels "no","yes": 2 2 2 2 2 2 1 1 2 2 ...
#> $ unemp : num 6.2 6.2 6.2 6.2 5.6 ...
#> $ wage : num 8.09 8.09 8.09 8.09 8.09 ...
#> $ distance : num 0.2 0.2 0.2 0.2 0.4 ...
#> $ tuition : num 0.889 0.889 0.889 0.889 0.889 ...
#> $ education: num 12 12 12 12 13 12 13 15 13 15 ...
#> $ income : Factor w/ 2 levels "low","high": 2 1 1 1 1 1 1 1 1 1 ...
#> $ region : Factor w/ 2 levels "other","west": 1 1 1 1 1 1 1 1 1 1 ...
#> - attr(*, "datalabel")= chr ""
#> - attr(*, "time.stamp")= chr "25 Oct 2002 16:44"
#> - attr(*, "formats")= chr [1:14] "%9.0g" "%9.0g" "%9.0g" "%9.0g" ...
#> - attr(*, "types")= int [1:14] 102 102 102 102 102 102 102 102 102 102 ...
#> - attr(*, "val.labels")= chr [1:14] "" "" "" "" ...
#> - attr(*, "var.labels")= chr [1:14] "" "" "" "" ...
#> - attr(*, "version")= int 6
#> - attr(*, "label.table")=List of 14
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
#> ..$ : NULL
| gender | ethnicity | score | fcollege | mcollege | home | urban | unemp | wage | distance | tuition | education | income | region |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| male | other | 39.15 | yes | no | yes | yes | 6.2 | 8.09 | 0.2 | 0.88915 | 12 | high | other |
| female | other | 48.87 | no | no | yes | yes | 6.2 | 8.09 | 0.2 | 0.88915 | 12 | low | other |
| male | other | 48.74 | no | no | yes | yes | 6.2 | 8.09 | 0.2 | 0.88915 | 12 | low | other |
| male | afam | 40.40 | no | no | yes | yes | 6.2 | 8.09 | 0.2 | 0.88915 | 12 | low | other |
| female | other | 40.48 | no | no | no | yes | 5.6 | 8.09 | 0.4 | 0.88915 | 13 | low | other |
| male | other | 54.71 | no | no | yes | yes | 5.6 | 8.09 | 0.4 | 0.88915 | 12 | low | other |
In this section we practice computing means, standard errors, and 95% CIs; running one-sample t-tests; running difference-in-means tests; running regressions; and including interaction terms.
Compute the mean, SE, and confidence interval manually.
mean_y <- mean(y)
sd_y <- sd(y)
n <- length(y)
se_y <- sd_y / sqrt(n)
CI_lower <- mean_y - 1.96 * se_y
CI_upper <- mean_y + 1.96 * se_y
mean_y#> [1] 50.88903
#> [1] 0.126407
#> [1] 50.64127 51.13679
One-sample t-test (\(H_0: \mu = 0\) vs. \(H_1: \mu \neq 0\)).
#>
#> One Sample t-test
#>
#> data: y
#> t = 402.58, df = 4738, p-value < 2.2e-16
#> alternative hypothesis: true mean is not equal to 0
#> 95 percent confidence interval:
#> 50.64121 51.13685
#> sample estimates:
#> mean of x
#> 50.88903
One-sided t-test (\(H_0: \mu \geq 50\) vs. \(H_1: \mu < 50\)).
#>
#> One Sample t-test
#>
#> data: y
#> t = 7.0331, df = 4738, p-value = 1
#> alternative hypothesis: true mean is less than 50
#> 95 percent confidence interval:
#> -Inf 51.09699
#> sample estimates:
#> mean of x
#> 50.88903
Compute the difference in mean scores manually, two ways.
# Method 1: index the score vector directly
mean_female <- mean(college$score[college$female_bi == 1])
mean_male <- mean(college$score[college$female_bi == 0])
diff_means <- mean_female - mean_male
diff_means#> [1] -1.401749
# Method 2: subset()
mean_female2 <- mean(subset(college, female_bi == 1)$score)
mean_male2 <- mean(subset(college, female_bi == 0)$score)
diff_means2 <- mean_female2 - mean_male2
diff_means2#> [1] -1.401749
Two-sample t-test for the difference in means by gender (\(H_0: \mu_\text{female} - \mu_\text{male} = 0\)).
#>
#> Welch Two Sample t-test
#>
#> data: college$score by college$female_bi
#> t = 5.5096, df = 4472.2, p-value = 3.798e-08
#> alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
#> 95 percent confidence interval:
#> 0.9029613 1.9005360
#> sample estimates:
#> mean in group 0 mean in group 1
#> 51.65808 50.25633
Regression of score on gender and high income.
#>
#> Call:
#> lm(formula = score ~ female_bi + high_income, data = college)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -24.993 -6.739 0.207 6.647 23.437
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) 50.5953 0.2042 247.737 < 2e-16 ***
#> female_bi -1.2223 0.2498 -4.893 1.03e-06 ***
#> high_income 3.3481 0.2745 12.197 < 2e-16 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 8.543 on 4736 degrees of freedom
#> Multiple R-squared: 0.03669, Adjusted R-squared: 0.03628
#> F-statistic: 90.18 on 2 and 4736 DF, p-value: < 2.2e-16
In R, female_bi * high_income expands to
female_bi + high_income + female_bi:high_income — the two
main effects plus their interaction.
#>
#> Call:
#> lm(formula = score ~ female_bi * high_income, data = college)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -24.7725 -6.7071 0.2154 6.6654 23.5154
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) 50.6980 0.2236 226.772 < 2e-16 ***
#> female_bi -1.4034 0.2968 -4.728 2.33e-06 ***
#> high_income 3.0245 0.3968 7.622 2.99e-14 ***
#> female_bi:high_income 0.6205 0.5495 1.129 0.259
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 8.542 on 4735 degrees of freedom
#> Multiple R-squared: 0.03694, Adjusted R-squared: 0.03633
#> F-statistic: 60.55 on 3 and 4735 DF, p-value: < 2.2e-16
The fully written-out form gives the identical fit:
#>
#> Call:
#> lm(formula = score ~ female_bi + high_income + female_bi:high_income,
#> data = college)
#>
#> Residuals:
#> Min 1Q Median 3Q Max
#> -24.7725 -6.7071 0.2154 6.6654 23.5154
#>
#> Coefficients:
#> Estimate Std. Error t value Pr(>|t|)
#> (Intercept) 50.6980 0.2236 226.772 < 2e-16 ***
#> female_bi -1.4034 0.2968 -4.728 2.33e-06 ***
#> high_income 3.0245 0.3968 7.622 2.99e-14 ***
#> female_bi:high_income 0.6205 0.5495 1.129 0.259
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> Residual standard error: 8.542 on 4735 degrees of freedom
#> Multiple R-squared: 0.03694, Adjusted R-squared: 0.03633
#> F-statistic: 60.55 on 3 and 4735 DF, p-value: < 2.2e-16
Using the estimated coefficients, the predicted mean test score for each of the four groups in the interaction model:
| Group | Predicted mean score |
|---|---|
| Male & Low-income | 50.70 |
| Male & High-income | 53.72 |
| Female & Low-income | 49.30 |
| Female & High-income | 52.94 |
Key takeaways
t.test() handles one-sample and two-sample tests.x1 * x2 = x1 + x2 + x1:x2 (main effects
plus the interaction).Thank you all for your hard work this semester. You’ve done an amazing job throughout the course!