13.1 Revisiting sexual discrimination in the workplace
Here we load a couple necessary packages, load the data, and take a glimpse()
.
library(tidyverse)
protest <- read_csv("data/protest/protest.csv")
glimpse(protest)
## Observations: 129
## Variables: 6
## $ subnum <int> 209, 44, 124, 232, 30, 140, 27, 64, 67, 182, 85, 109, 122, 69, 45, 28, 170, 66...
## $ protest <int> 2, 0, 2, 2, 2, 1, 2, 0, 0, 0, 2, 2, 0, 1, 1, 0, 1, 2, 2, 1, 2, 1, 1, 2, 2, 0, ...
## $ sexism <dbl> 4.87, 4.25, 5.00, 5.50, 5.62, 5.75, 5.12, 6.62, 5.75, 4.62, 4.75, 6.12, 4.87, ...
## $ angry <int> 2, 1, 3, 1, 1, 1, 2, 1, 6, 1, 2, 5, 2, 1, 1, 1, 2, 1, 3, 4, 1, 1, 1, 5, 1, 5, ...
## $ liking <dbl> 4.83, 4.50, 5.50, 5.66, 6.16, 6.00, 4.66, 6.50, 1.00, 6.83, 5.00, 5.66, 5.83, ...
## $ respappr <dbl> 4.25, 5.75, 4.75, 7.00, 6.75, 5.50, 5.00, 6.25, 3.00, 5.75, 5.25, 7.00, 4.50, ...
With a little ifelse()
, we can make the D1
and D2
contrast-coded dummies.
protest <-
protest %>%
mutate(D1 = ifelse(protest == 0, -2/3, 1/3),
D2 = ifelse(protest == 0, 0,
ifelse(protest == 1, -1/2, 1/2)))
Load brms.
library(brms)
Here are the sub-model formulas.
m_model <- bf(respappr ~ 1 + D1 + D2 + sexism + D1:sexism + D2:sexism)
y_model <- bf(liking ~ 1 + D1 + D2 + respappr + sexism + D1:sexism + D2:sexism)
Now we’re ready to fit our primary model, the conditional process model with a multicategorical antecedent.
model1 <-
brm(data = protest, family = gaussian,
m_model + y_model + set_rescor(FALSE),
chains = 4, cores = 4)
Here’s the model summary, which coheres reasonably well with the output in Table 13.1.
print(model1, digits = 3)
## Family: MV(gaussian, gaussian)
## Links: mu = identity; sigma = identity
## mu = identity; sigma = identity
## Formula: respappr ~ 1 + D1 + D2 + sexism + D1:sexism + D2:sexism
## liking ~ 1 + D1 + D2 + respappr + sexism + D1:sexism + D2:sexism
## Data: protest (Number of observations: 129)
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
## total post-warmup samples = 4000
##
## Population-Level Effects:
## Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
## respappr_Intercept 4.587 0.681 3.239 5.957 4000 0.999
## liking_Intercept 3.478 0.633 2.243 4.705 4000 1.000
## respappr_D1 -2.876 1.443 -5.675 -0.031 3545 1.000
## respappr_D2 1.672 1.622 -1.624 4.845 3595 1.001
## respappr_sexism 0.045 0.132 -0.213 0.312 4000 0.999
## respappr_D1:sexism 0.843 0.280 0.294 1.386 3575 1.000
## respappr_D2:sexism -0.244 0.311 -0.854 0.387 3579 1.001
## liking_D1 -2.690 1.154 -5.001 -0.447 3523 1.000
## liking_D2 0.069 1.334 -2.531 2.632 3310 1.001
## liking_respappr 0.364 0.073 0.220 0.507 4000 1.000
## liking_sexism 0.074 0.104 -0.127 0.273 4000 1.000
## liking_D1:sexism 0.519 0.228 0.074 0.960 3488 1.000
## liking_D2:sexism -0.042 0.255 -0.537 0.457 3358 1.000
##
## Family Specific Parameters:
## Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
## sigma_respappr 1.149 0.075 1.013 1.307 4000 1.001
## sigma_liking 0.917 0.060 0.805 1.041 4000 0.999
##
## Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
## is a crude measure of effective sample size, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
The tidybayes::geom_halfeyeh()
function gives us a nice way to look at the output with a coefficient plot.
library(tidybayes)
post <- posterior_samples(model1)
post %>%
select(starts_with("b_")) %>%
gather() %>%
mutate(criterion = ifelse(str_detect(key, "respappr"), "criterion: respappr", "criterion: liking"),
criterion = factor(criterion, levels = c("criterion: respappr", "criterion: liking")),
key = str_remove(key, "b_respappr_"),
key = str_remove(key, "b_liking_"),
key = factor(key, levels = c("Intercept", "respappr", "D2:sexism", "D1:sexism", "sexism", "D2", "D1"))) %>%
ggplot(aes(x = value, y = key, group = key)) +
geom_halfeyeh(.prob = c(0.95, 0.5),
scale = "width", relative_scale = .75,
color = "white") +
coord_cartesian(xlim = c(-7, 6)) +
labs(x = NULL, y = NULL) +
theme_black() +
theme(axis.text.y = element_text(hjust = 0),
axis.ticks.y = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "grey20")) +
facet_wrap(~criterion)
The Bayesian \(R^2\) distributions are reasonably close to the estimates in the text.
bayes_R2(model1) %>% round(digits = 3)
## Estimate Est.Error Q2.5 Q97.5
## R2_respappr 0.320 0.052 0.213 0.413
## R2_liking 0.294 0.055 0.181 0.397