# Load librarieslibrary(tidyverse)library(dagitty)library(ggdag)library(GGally)library(ggpmisc)library(gt)library(cmdstanr)library(tidybayes)library(ggridges)library(loo)#library(posterior)# Set ggplot themetheme_set(theme_classic())# Create a function to convert decimals to percentagesto_percent <-function(x, digits =0){return(round(x *100, digits = digits))}# Custom lower panel with regression line, equation, and styled pointslower_fun <-function(data, mapping, ...) {ggplot(data = data, mapping = mapping) +geom_point(shape =1, alpha =0.4, size =1.5) +geom_smooth(method ="lm", formula ='y ~ x', se =FALSE, color ="steelblue") +geom_abline(intercept =0, slope =1, linetype ="dashed") +stat_poly_eq(formula = y ~ x,aes(label =after_stat(eq.label)),parse =TRUE,size =3 ) +scale_x_continuous(labels = scales::percent, breaks =seq(-1,1, 0.25)) +scale_y_continuous(labels = scales::percent, breaks =seq(-1,1, 0.250))}
It’s sensible to assume that the teacher has a systematic impact on student achievement for two reasons. First, they are often the ones grading students and some teachers can be more lenient or harsher graders than others. Second, some teachers may be better or worse than others at teaching which would impact performance on tests. Given that it’s easy to collect information on who the teacher was, let’s add it to our DAG as seen in Figure 5.1.
Figure 5.1: Hierarchical DAG with the effect of the teacher.
5.1 Mathematical Model
\[\text{logit}(\mu_{8i}) = \tau_{8j} + \alpha_8\]
\[\phi_8, \phi_9, \phi_{10} \sim N^+(10, 3)\]
\[x_{8i} \sim \text{Beta}(\mu_{8i} \cdot \phi_8, \, (1 - \mu_{8i}) \cdot \phi_8))\]\[\text{logit}(\mu_{9i}) = \tau_{9j} + \alpha_9 + \beta_1 \cdot (x_{8i} - \bar{x}_8)\]\[x_{9i} \sim \text{Beta}(\mu_{9i} \cdot \phi_9,\ (1 - \mu_{9i}) \cdot \phi_9)\]\[\text{logit}(\mu_{10i}) = \tau_{10j} + \alpha_{10} + \beta_2 \cdot (x_{8i} - \bar{x}_8) + \beta_3 \cdot (x_{9i} - \bar{x}_9)\]\[y_{10i} \sim \text{Beta}(\mu_{10i} \cdot \phi_{10},\ (1 - \mu_{10i}) \cdot \phi_{10})\] Let’s try to write some reasonable priors for the \(\alpha\) and \(\tau\) parameters. Alpha represents the expected log-odds grade for the average student. In the previous chapters we assumed that the average student would finish with 80%, 77%, and 72% in year 8, 9, 10 respectively. Thus, we could set the following priors.
\[\alpha_8 \sim N(1.4, 0.03)\]\[\alpha_9 \sim N(1.2, 0.03)\]\[\alpha_{10} \sim N(0.95, 0.03)\] Now let’s pivot to focus on the \(\tau\) parameters which represent the teacher effects.We know some teacher’s are harsher than others but we can assume than the average teacher is a relatively grader. In other words, we assume that teacher bias is a random error of measurement instead of a systematic one. It’s entirely possible that teachers are systematically too generous in their grading because they want their students to succeed.
As seen in Figure 5.2 a one unit increase in log-odds represents roughly a 20% difference in student grades. We don’t expect teacher effects to be this strong so we might set the following prior.
student teacher_8 bias_8 teacher_9
Min. : 1.00 Length:250 Min. :-0.3000 Length:250
1st Qu.: 63.25 Class :character 1st Qu.:-0.3000 Class :character
Median :125.50 Mode :character Median : 0.0000 Mode :character
Mean :125.50 Mean : 0.0184
3rd Qu.:187.75 3rd Qu.: 0.2500
Max. :250.00 Max. : 0.2500
bias_9 teacher_10 bias_10 mu8
Min. :-0.500 Length:250 Min. :-0.3000 Min. :0.7484
1st Qu.:-0.500 Class :character 1st Qu.:-0.3000 1st Qu.:0.7484
Median : 0.000 Mode :character Median : 0.2000 Median :0.8006
Mean :-0.162 Mean : 0.0808 Mean :0.8007
3rd Qu.: 0.000 3rd Qu.: 0.2000 3rd Qu.:0.8375
Max. : 0.200 Max. : 0.4000 Max. :0.8375
y8 mu9 y9 mu10
Min. :0.4064 Min. :0.2449 Min. :0.2017 Min. :0.1585
1st Qu.:0.7011 1st Qu.:0.6279 1st Qu.:0.6307 1st Qu.:0.5927
Median :0.8125 Median :0.7600 Median :0.7699 Median :0.7753
Mean :0.7912 Mean :0.7193 Mean :0.7292 Mean :0.7057
3rd Qu.:0.8915 3rd Qu.:0.8353 3rd Qu.:0.8697 3rd Qu.:0.8512
Max. :0.9933 Max. :0.9184 Max. :0.9899 Max. :0.9323
y10
Min. :0.1111
1st Qu.:0.5641
Median :0.7668
Mean :0.7096
3rd Qu.:0.8868
Max. :1.0000
We see that our data is realistic and that teacher effects do indeed shift the distributions. Let’s focus our attention on the three teachers in year 9.
Code
sim_grades_by_teacher |>filter(student_grade ==9) |>ggplot(aes(x = result, fill = teacher)) +geom_density(alpha =0.5) +stat_function(fun = dbeta,args =list(shape1 =0.77*10, shape2 = (1-0.77)*10),xlim =c(0,1),size =3, color ="darkorange" ) +geom_vline(xintercept =0.5, linetype ="dashed") +scale_x_continuous(breaks =seq(0, 1, 0.1),labels = scales::percent) +labs(title ="Bias: E = 0, F = -0.5, G = 0.2",,subtitle ="The orange line is the theoretical density",x ="Simulated Year 9 Grades",y ="Probability Density" )
We see that the green distribution is shifted to the left relative to the orange curve because of the negative bias of -0.5 on the log-odd scale. Conversely, the blue distribution is slightly shifted to the right while the red distribution roughly follows the theoretical distribution.
5.3 Consistent Teacher Effects
The previous simulation assumed that the teacher effects were independent between years. That is, a harsh grader in year 9 was no more likely to be a grader in year 10 than a easy grader. It seems reasonable to assume that some teachers are systematically harsher teachers than others across grades and that their bias may differ for different courses.
# A tibble: 250 × 10
student teacher_8 teacher_9 teacher_10 zeta_8 zeta_9 zeta_10 tau_8 tau_9
<int> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 D F H 0.382 -0.0489 -0.0240 0.421 -0.0834
2 2 D E H 0.382 0.111 -0.0240 0.421 0.103
3 3 D F H 0.382 -0.0489 -0.0240 0.421 -0.0834
4 4 D F G 0.382 -0.0489 0.119 0.421 -0.0834
5 5 D F H 0.382 -0.0489 -0.0240 0.421 -0.0834
6 6 B G G 0.0107 0.119 0.119 0.0478 0.189
7 7 D F F 0.382 -0.0489 -0.0489 0.421 -0.0834
8 8 A E F 0.186 0.111 -0.0489 0.313 0.103
9 9 D F H 0.382 -0.0489 -0.0240 0.421 -0.0834
10 10 C E G 0.232 0.111 0.119 0.216 0.103
# ℹ 240 more rows
# ℹ 1 more variable: tau_10 <dbl>
student teacher_8 teacher_9 teacher_10
Min. : 1.00 Length:250 Length:250 Length:250
1st Qu.: 63.25 Class :character Class :character Class :character
Median :125.50 Mode :character Mode :character Mode :character
Mean :125.50
3rd Qu.:187.75
Max. :250.00
zeta_8 zeta_9 zeta_10 tau_8
Min. :0.01069 Min. :-0.04886 Min. :-0.04886 Min. :0.04779
1st Qu.:0.23195 1st Qu.:-0.04886 1st Qu.:-0.04886 1st Qu.:0.21566
Median :0.23195 Median : 0.11129 Median :-0.02400 Median :0.31348
Mean :0.27591 Mean : 0.04816 Mean : 0.03618 Mean :0.30405
3rd Qu.:0.38175 3rd Qu.: 0.11129 3rd Qu.: 0.11913 3rd Qu.:0.42146
Max. :0.38175 Max. : 0.11913 Max. : 0.11913 Max. :0.42146
tau_9 tau_10 mu8 y8
Min. :-0.08335 Min. :0.01322 Min. :0.8081 Min. :0.4241
1st Qu.:-0.08335 1st Qu.:0.01322 1st Qu.:0.8328 1st Qu.:0.7625
Median : 0.10329 Median :0.05332 Median :0.8460 Median :0.8640
Mean : 0.04510 Mean :0.07351 Mean :0.8440 Mean :0.8346
3rd Qu.: 0.10329 3rd Qu.:0.12270 3rd Qu.:0.8595 3rd Qu.:0.9323
Max. : 0.18935 Max. :0.12270 Max. :0.8595 Max. :0.9927
mu9 y9 mu10 y10
Min. :0.2838 Min. :0.1072 Min. :0.08653 Min. :0.0379
1st Qu.:0.7091 1st Qu.:0.6789 1st Qu.:0.63449 1st Qu.:0.5636
Median :0.8019 Median :0.8044 Median :0.77314 Median :0.7685
Mean :0.7617 Mean :0.7641 Mean :0.71230 Mean :0.7057
3rd Qu.:0.8520 3rd Qu.:0.9004 3rd Qu.:0.83975 3rd Qu.:0.8688
Max. :0.8913 Max. :0.9948 Max. :0.89775 Max. :0.9993
# Compile the Stan Modelteacher_mod <-cmdstan_model(stan_file ='stan_models/teacher_model.stan')# Fit the modelfit_teacher_mod <- teacher_mod$sample(dat = data_list,seed =2025 )# Save the Stan modelfit_teacher_mod$save_object(file ="stan_models/fit_teacher_mod.RDS")fit_teacher_mod$cmdstan_diagnose()rm("teacher_mod", "fit_teacher_mod")
Code
# Load the Stan modelfit_teacher_mod <-readRDS("stan_models/fit_teacher_mod.RDS")
Computed from 4000 by 250 log-likelihood matrix.
Estimate SE
elpd_loo 202.0 11.1
p_loo 4.9 0.5
looic -404.0 22.1
------
MCSE of elpd_loo is 0.0.
MCSE and ESS estimates assume MCMC draws (r_eff in [0.8, 1.6]).
All Pareto k estimates are good (k < 0.7).
See help('pareto-k-diagnostic') for details.