Discussion 2. Analyzing an Experiment in R
STSCI/INFO/ILRST 3900: Causal Inference
Announcements
- Office Hours throughout the week (see Syllabus or website)
- Filippo: Thursday 4-5pm in 325A CIS Building
- Shira: Monday 5-6 pm in 325A CIS Building
- No need to submit, encouraged to complete the file and knit
- In-class assignments will start later in the semester
Generative AI and Math Learning Experiment
- How generative AI affects learning?
- GenAI already shown to improve human productivity
- Is GenAI an effective tutor, or does it become a cognitive crutch?
- Research Question: To what extent does access to GenAI (with and without guardrails) affect learning in an educational setting?
- Article: “Generative AI without guardrails can harm learning: Evidence from high school mathematics”
- We’ll be analyzing their experiment today!
Experimental Design
- Nearly 1,000 high school students in Turkey were randomly assigned 1 of 3
- High school math students were randomly assigned to one of three treatment arms:
- Control: Standard practice material with no AI assistance access
- GPT Base: Access to standard GPT-4
- GPT Tutor: Access to a customized GPT-4 (GenAI with guardrails)
- Following this practice session, all students took an exam without AI access to evaluate learning
Goal for Today
Replicate Something Similar to Table A.1 (in appendix) and Table 1
- Table A.1 demonstrates balance of covariates across treatment arms
- This ensures treatment assignment is randomized so exchangeability holds
- Table 1 shows the main results of student performance in the practice and exam problems
- Identify the average Treatment effect (ATE) utilizing randomization \[ACE = E[Y^\text{a=1}]- E[Y^\text{a=0}] = E[Y \mid A=1]-E[Y\mid A=0]\]
Resources for Markdown
- Hadley Wickham’s R for Data Science “Chapter 27”
- “RMarkdown cheat sheet” from RStudio
- “Data Wrangling and Analyses with Tidyverse” by Bookdown
- “RMarkdown for Scientists” by Nicholas Tierney
- If you can’t figure out how to do something, try Googling it first!
- Also feel free to ask a classmate or ask me :)
Step 1: Download the .Rmd file here
- Start by running the code in Section “Necessary packages”
- If you get an error, you may need to install the package
Step 2: Import and Clean the Data
genAI_dta <- read_csv("https://raw.githubusercontent.com/causal3900/causal3900.github.io/refs/heads/main/assets/discussions/discussion02_files/GenAI_Learning.csv")- Quick peek at the dataset using the function
glimpse - Notice the variable
Honors - Notice the treatment variables
GPTBaseandGPTTutor
glimpse(genAI_dta)- …students are randomly assigned to classrooms (with the exception of honors-designated classrooms)…
- Exclude honors-designated classrooms from the sample
- For this, you will want to use the function
filter - The general syntax is
filter(condition) - A condition would be
Honors == 0
genAI_dta <- genAI_dta %>%
filter(...)- Create a single treatment variable with word labels:
- “Control”: If
GPTBase == 0andGPTTutor == 0 - “GPTBase”: If
GPTBase == 1andGPTTutor == 0 - “GPTTutor”: If
GPTBase == 0andGPTTutor == 1
- “Control”: If
- For this, you will want to use the function
case_whenwhich is described here - The general syntax is
case_when(condition ~ output-value) - A condition would be
(GPTBase == 0) & (GPTTutor == 0)and an output value would be"Control"
genAI_dta <- genAI_dta %>%
mutate(treatment = case_when(...)) Step 3: Table A.1
- Is the data balanced on covariates?
- We want to check that the treatment groups are balanced on covariates
- For each treatment arm/group, calculate the mean for each of the designated covariates in table A.1 (list given below)
- Use
group_by()to calculate separate means for each treatment arm - Use
summarise()to compute the mean of each covariate incovariates
covariates <- c("education_parent_college", "n_household_members",
"n_household_children", "class_enjoyment",
"class_participation_likelihood", "math_hw_completion", "hw_help",
"private_tutorship","visit_training_center","female",
"n_weekday_study_hours","n_weekend_study_hours","gpa_prev")
genAI_balance <- genAI_dta |>
distinct(`Student ID`, .keep_all = TRUE) |>
group_by(...) |>
summarise(across(all_of(...),\(x) mean(x, na.rm = TRUE)))
genAI_balance |>
pivot_longer(-treatment, names_to = "Description", values_to = "value") |>
pivot_wider(names_from = treatment, values_from = "value") |>
select(Description, GPTTutor, Control, GPTBase) |>
print()Step 4: Table 1
- What are the main results of the experiment?
- For each treatment arm, calculate the average grade of students in the:
- Practice problems (
Part2Tot) - Exam problems (
Part3Tot)
- Practice problems (
- Use
group_by()to calculate separate means for each treatment arm - Use
summarise()to do the following:- Create a column
Practice_perf- the average grade in step 2 of each group - Create a column
Exam_perf- the average grade in step 3 of each group
- Create a column
- Note that your numbers will not match up exactly with Table 1
genAI_means <-
genAI_dta %>%
group_by(...) %>%
summarise(Practice_perf = mean(...),
Exam_perf = mean(...))
print(genAI_means)- Use the sample means to estimate the average treatment effect
Example from Lecture
- Given potential outcomes, you chose a diet
- Are \((Y^{a=0},Y^{a=1}) \perp\!\!\!\perp A\)?
- Observational setting: no access to potential outcomes, only observed outcome
| \(Y_i = \text{Disease } (0)\) | \(Y_i = \text{No Disease } (1)\) | |
|---|---|---|
| \(A_i = \text{Delicious } (0)\) | 20 | 54 |
| \(A_i = \text{Healthy } (1)\) | 0 | 64 |
\[\widehat{ATE} = E(Y \mid A = 1) - E(Y \mid A = 0) = \frac{64}{0+64}- \frac{54}{20+54} \approx 0.27\]
True ATE
- 50% of students have \(Y_i^{\text{Delicious}} = 1\), \(Y_i^{\text{Healthy}} = 1\)
- 50% of students have \(Y_i^{\text{Delicious}} = 0\), \(Y_i^{\text{Healthy}} = 1\)
- \(Y_i^{\text{Delicious}} \sim Bernoulli(0.5)\)
- \(Y_i^{\text{Healthy}} \sim Bernoulli(1)\)
\[ATE = E(Y^{\text{Healthy}}) - E(Y^{\text{Delicious}}) = 1-0.5 = 0.5\]
Assume a Randomized Trial
n <- 138
Y1 <- rep(1,n)
Y0 <- c(rep(0,n/2),
rep(1,n/2))
set.seed(1231)
A <- rbinom(n, 1, 0.5)
Y <- ifelse(test = (A==1), yes = Y1, no = Y0)
print(table(A,Y))## Y
## A 0 1
## 0 37 41
## 1 0 60
| \(Y_i = \text{Disease } (0)\) | \(Y_i = \text{No Disease } (1)\) | |
|---|---|---|
| \(A_i = \text{Delicious } (0)\) | 37 | 41 |
| \(A_i = \text{Healthy } (1)\) | 0 | 60 |
\[\widehat{ATE} = E(Y \mid A = 1) - E(Y \mid A = 0) = \frac{60}{0+60}- \frac{41}{41+37} \approx 0.47\]