Set up

# Load libraries 
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(afex)
## Loading required package: lme4
## Loading required package: Matrix
## ************
## Welcome to afex. For support visit: http://afex.singmann.science/
## - Functions for ANOVAs: aov_car(), aov_ez(), and aov_4()
## - Methods for calculating p-values with mixed(): 'S', 'KR', 'LRT', and 'PB'
## - 'afex_aov' and 'mixed' objects can be passed to emmeans() for follow-up tests
## - Get and set global package options with: afex_options()
## - Set sum-to-zero contrasts globally: set_sum_contrasts()
## - For example analyses see: browseVignettes("afex")
## ************
## 
## Attaching package: 'afex'
## The following object is masked from 'package:lme4':
## 
##     lmer
library(emmeans)
library(readr)
library(ggplot2)

# Read in data -----------
dat = read.csv("data/intent-ability-whitestim-b-w-a-models-clean.csv")
dat$race_cond = as.factor(dat$race_cond)

options(scipen=999)
afex::set_sum_contrasts()
## setting contr.sum globally: options(contrasts=c('contr.sum', 'contr.poly'))
contrasts(dat$race_cond) 
##       [,1] [,2]
## asian    1    0
## black    0    1
## white   -1   -1

Intent Model

# Linear 
mod1_intent = mixed(intent ~ sd_level*race_cond + (sd_level*race_cond ||ResponseId) + 
                      (sd_level*race_cond ||base), 
                    data = dat, expand_re = TRUE)
## boundary (singular) fit: see help('isSingular')
summary(mod1_intent)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: intent ~ sd_level * race_cond + (1 + re1.sd_level + re1.race_cond1 +  
##     re1.race_cond2 + re1.sd_level_by_race_cond1 + re1.sd_level_by_race_cond2 ||  
##     ResponseId) + (1 + re2.sd_level + re2.race_cond1 + re2.race_cond2 +  
##     re2.sd_level_by_race_cond1 + re2.sd_level_by_race_cond2 ||      base)
##    Data: data
## 
## REML criterion at convergence: 39521.8
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.2071 -0.5983  0.0438  0.6100  5.7801 
## 
## Random effects:
##  Groups       Name                       Variance        Std.Dev.  
##  ResponseId   (Intercept)                0.3887682244208 0.62351281
##  ResponseId.1 re1.sd_level               0.0061704260930 0.07855206
##  ResponseId.2 re1.race_cond1             0.0000000004637 0.00002153
##  ResponseId.3 re1.race_cond2             0.0051687415018 0.07189396
##  ResponseId.4 re1.sd_level_by_race_cond1 0.0000000000000 0.00000000
##  ResponseId.5 re1.sd_level_by_race_cond2 0.0001972749689 0.01404546
##  base         (Intercept)                0.0299473193298 0.17305294
##  base.1       re2.sd_level               0.0006171268274 0.02484204
##  base.2       re2.race_cond1             0.0000000321817 0.00017939
##  base.3       re2.race_cond2             0.0000000030443 0.00005518
##  base.4       re2.sd_level_by_race_cond1 0.0000000001271 0.00001128
##  base.5       re2.sd_level_by_race_cond2 0.0000531195695 0.00728832
##  Residual                                1.0051869910684 1.00259014
## Number of obs: 13425, groups:  ResponseId, 179; base, 25
## 
## Fixed effects:
##                                Estimate          Std. Error                  df
## (Intercept)             3.6318050812348     0.0586981713633   107.7439508105619
## sd_level               -0.2324479371261     0.0078429588067    81.8131854128698
## race_cond1             -0.0304655541434     0.0122372308452 11992.0155735671979
## race_cond2             -0.0356052143096     0.0133650402276   284.6417380717882
## sd_level:race_cond1    -0.0000000000373     0.0021632490788 12573.8184417872581
## sd_level:race_cond2     0.0198977248097     0.0028121246667    41.8494320208125
##                     t value             Pr(>|t|)    
## (Intercept)          61.873 < 0.0000000000000002 ***
## sd_level            -29.638 < 0.0000000000000002 ***
## race_cond1           -2.490              0.01280 *  
## race_cond2           -2.664              0.00816 ** 
## sd_level:race_cond1   0.000              1.00000    
## sd_level:race_cond2   7.076         0.0000000116 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) sd_lvl rc_cn1 rc_cn2 sd_:_1
## sd_level     0.000                            
## race_cond1   0.000  0.000                     
## race_cond2   0.000  0.000 -0.458              
## sd_lvl:rc_1  0.000  0.000  0.000  0.000       
## sd_lvl:rc_2  0.000  0.000  0.000  0.000 -0.385
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
# Quadratic 
mod2_intent = mixed(intent ~ sd_level + race_cond + sd_level:race_cond + I(sd_level^2) +  
                      (sd_level*race_cond||ResponseId) + (sd_level*race_cond||base), 
                    data = dat, expand_re = TRUE)
## boundary (singular) fit: see help('isSingular')
summary(mod2_intent)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: intent ~ sd_level + race_cond + sd_level:race_cond + I(sd_level^2) +  
##     (1 + re1.sd_level + re1.race_cond1 + re1.race_cond2 + re1.sd_level_by_race_cond1 +  
##         re1.sd_level_by_race_cond2 || ResponseId) + (1 + re2.sd_level +  
##     re2.race_cond1 + re2.race_cond2 + re2.sd_level_by_race_cond1 +  
##     re2.sd_level_by_race_cond2 || base)
##    Data: data
## 
## REML criterion at convergence: 38320
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.8030 -0.5548 -0.0260  0.5401  5.7330 
## 
## Random effects:
##  Groups       Name                       Variance        Std.Dev.  
##  ResponseId   (Intercept)                0.3898113862135 0.62434877
##  ResponseId.1 re1.sd_level               0.0062072190060 0.07878591
##  ResponseId.2 re1.race_cond1             0.0000000000000 0.00000000
##  ResponseId.3 re1.race_cond2             0.0070034731472 0.08368676
##  ResponseId.4 re1.sd_level_by_race_cond1 0.0000000000000 0.00000000
##  ResponseId.5 re1.sd_level_by_race_cond2 0.0002539462137 0.01593569
##  base         (Intercept)                0.0301112324802 0.17352588
##  base.1       re2.sd_level               0.0006215598025 0.02493110
##  base.2       re2.race_cond1             0.0000000004847 0.00002202
##  base.3       re2.race_cond2             0.0000000030705 0.00005541
##  base.4       re2.sd_level_by_race_cond1 0.0000000000000 0.00000000
##  base.5       re2.sd_level_by_race_cond2 0.0000601068906 0.00775286
##  Residual                                0.9131302307860 0.95557848
## Number of obs: 13425, groups:  ResponseId, 179; base, 25
## 
## Fixed effects:
##                                         Estimate                   Std. Error
## (Intercept)             3.2796412160438386251826     0.0595665388910883719653
## sd_level               -0.2324480105896724047021     0.0078537028092123869344
## race_cond1             -0.0304655494264724803488     0.0116633750784500018344
## race_cond2             -0.0356052143109821181421     0.0132348014745728610742
## I(sd_level^2)           0.0110052540569301974399     0.0003080421990283515959
## sd_level:race_cond1    -0.0000000000000000008929     0.0020618127553014052936
## sd_level:race_cond2     0.0198985214581194058692     0.0028417771196621180799
##                                               df t value             Pr(>|t|)
## (Intercept)           114.3432475542602162477124  55.058 < 0.0000000000000002
## sd_level               82.4628716071241143481529 -29.597 < 0.0000000000000002
## race_cond1          12632.0744243883164017461240  -2.612              0.00901
## race_cond2            273.8777596397180786880199  -2.690              0.00758
## I(sd_level^2)       12647.5940046301129768835381  35.726 < 0.0000000000000002
## sd_level:race_cond1 12647.5940050547960709081963   0.000              1.00000
## sd_level:race_cond2    43.7250170283717096708642   7.002         0.0000000117
##                        
## (Intercept)         ***
## sd_level            ***
## race_cond1          ** 
## race_cond2          ** 
## I(sd_level^2)       ***
## sd_level:race_cond1    
## sd_level:race_cond2 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) sd_lvl rc_cn1 rc_cn2 I(_^2) sd_:_1
## sd_level     0.000                                   
## race_cond1   0.000  0.000                            
## race_cond2   0.000  0.000 -0.441                     
## I(sd_lvl^2) -0.165  0.000  0.000  0.000              
## sd_lvl:rc_1  0.000  0.000  0.000  0.000  0.000       
## sd_lvl:rc_2  0.000  0.000  0.000  0.000  0.000 -0.363
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
# Model comparison
anova(mod1_intent, mod2_intent, refit = TRUE)
## refitting model(s) with ML (instead of REML)
## Data: data
## Models:
## mod1_intent: intent ~ sd_level * race_cond + (1 + re1.sd_level + re1.race_cond1 + re1.race_cond2 + re1.sd_level_by_race_cond1 + re1.sd_level_by_race_cond2 || ResponseId) + (1 + re2.sd_level + re2.race_cond1 + re2.race_cond2 + re2.sd_level_by_race_cond1 + re2.sd_level_by_race_cond2 || base)
## mod2_intent: intent ~ sd_level + race_cond + sd_level:race_cond + I(sd_level^2) + (1 + re1.sd_level + re1.race_cond1 + re1.race_cond2 + re1.sd_level_by_race_cond1 + re1.sd_level_by_race_cond2 || ResponseId) + (1 + re2.sd_level + re2.race_cond1 + re2.race_cond2 + re2.sd_level_by_race_cond1 + re2.sd_level_by_race_cond2 || base)
##             npar   AIC   BIC logLik deviance  Chisq Df            Pr(>Chisq)
## mod1_intent   19 39514 39656 -19738    39476                                
## mod2_intent   20 38299 38449 -19130    38259 1216.2  1 < 0.00000000000000022
##                
## mod1_intent    
## mod2_intent ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Post-hoc trends 
emtrends(mod2_intent, pairwise ~ race_cond, var = "sd_level", pbkrtest.limit = 13425)
## $emtrends
##  race_cond sd_level.trend      SE  df lower.CL upper.CL
##  asian             -0.232 0.00812 101   -0.248   -0.216
##  black             -0.212 0.00835 111   -0.229   -0.196
##  white             -0.252 0.00835 110   -0.269   -0.236
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95 
## 
## $contrasts
##  contrast      estimate      SE    df t.ratio p.value
##  asian - black  -0.0199 0.00407 150.8  -4.887  <.0001
##  asian - white   0.0199 0.00407  27.6   4.887  0.0001
##  black - white   0.0398 0.00530  33.1   7.514  <.0001
## 
## Degrees-of-freedom method: kenward-roger 
## P value adjustment: tukey method for comparing a family of 3 estimates

Plot the data

plot_grid <- ref_grid(mod2_intent$full_model, at = list(sd_level = c(-8, -4,  0, 4, 8)))
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'pbkrtest.limit = 13425' (or larger)
## [or, globally, 'set emm_options(pbkrtest.limit = 13425)' or larger];
## but be warned that this may result in large computation time and memory use.
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'lmerTest.limit = 13425' (or larger)
## [or, globally, 'set emm_options(lmerTest.limit = 13425)' or larger];
## but be warned that this may result in large computation time and memory use.
plot_dat <- emmeans(plot_grid, specs = "sd_level", by = "race_cond")

plot_dat <- as.data.frame(plot_dat)

p1 = ggplot(data = plot_dat, aes(x = sd_level, y = emmean, color = race_cond, ymin = asymp.LCL, ymax = asymp.UCL)) +
  geom_line(position = position_dodge(0.5)) +
  geom_point(size = 2, position = position_dodge(0.5)) +
  geom_errorbar(width = 0.5, position = position_dodge(0.5), show.legend = FALSE) +
  ylim(1,7) +
  labs(x = "Trustworthiness Dimension (SD)", y = "Intends to Harm") +
  scale_x_continuous(breaks = c(-8, -4, 0, 4, 8)) +
  scale_color_discrete(name = "", breaks = c("black", "white", "asian"),
                       labels = c("Black Model", "White Model", "East Asian Model")) +
  theme(legend.position = "top",
        legend.key = element_blank())

p1

Changing Contrasts for Intent

dat <- dat |> 
  mutate(race_cond2 = case_match(race_cond,
    "asian" ~ "3asian",
    "black" ~ "1black",
    "white" ~ "2white"
  ))

dat$race_cond2 <- forcats::fct(dat$race_cond2, levels = c("1black", "2white", "3asian"))

contrasts(dat$race_cond2)
##        [,1] [,2]
## 1black    1    0
## 2white    0    1
## 3asian   -1   -1
mod2b_intent <- mixed(intent ~ sd_level + race_cond2 + sd_level:race_cond2 + I(sd_level^2) +  
                        (sd_level*race_cond2||ResponseId) + (sd_level*race_cond2||base), 
                      data = dat, expand_re = TRUE)
## boundary (singular) fit: see help('isSingular')
summary(mod2b_intent)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: 
## intent ~ sd_level + race_cond2 + sd_level:race_cond2 + I(sd_level^2) +  
##     (1 + re1.sd_level + re1.race_cond21 + re1.race_cond22 + re1.sd_level_by_race_cond21 +  
##         re1.sd_level_by_race_cond22 || ResponseId) + (1 + re2.sd_level +  
##     re2.race_cond21 + re2.race_cond22 + re2.sd_level_by_race_cond21 +  
##     re2.sd_level_by_race_cond22 || base)
##    Data: data
## 
## REML criterion at convergence: 38345.7
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.9226 -0.5573 -0.0266  0.5414  5.5736 
## 
## Random effects:
##  Groups       Name                        Variance        Std.Dev.  
##  ResponseId   (Intercept)                 0.3898844440048 0.62440727
##  ResponseId.1 re1.sd_level                0.0062030514707 0.07875945
##  ResponseId.2 re1.race_cond21             0.0000000005646 0.00002376
##  ResponseId.3 re1.race_cond22             0.0000000000000 0.00000000
##  ResponseId.4 re1.sd_level_by_race_cond21 0.0000826528924 0.00909136
##  ResponseId.5 re1.sd_level_by_race_cond22 0.0000000000000 0.00000000
##  base         (Intercept)                 0.0300225052025 0.17327004
##  base.1       re2.sd_level                0.0006210881603 0.02492164
##  base.2       re2.race_cond21             0.0000000000000 0.00000000
##  base.3       re2.race_cond22             0.0000001716246 0.00041428
##  base.4       re2.sd_level_by_race_cond21 0.0000254348824 0.00504330
##  base.5       re2.sd_level_by_race_cond22 0.0000080355798 0.00283471
##  Residual                                 0.9222493995394 0.96033817
## Number of obs: 13425, groups:  ResponseId, 179; base, 25
## 
## Fixed effects:
##                           Estimate    Std. Error            df t value
## (Intercept)              3.2796387     0.0595540   114.8583211  55.070
## sd_level                -0.2324480     0.0078524    82.4025717 -29.602
## race_cond21             -0.0356052     0.0117215 12792.2697731  -3.038
## race_cond22              0.0660708     0.0117218  5606.9912831   5.637
## I(sd_level^2)            0.0110053     0.0003096 12792.3962547  35.549
## sd_level:race_cond21     0.0198986     0.0024028    37.7465589   8.281
## sd_level:race_cond22    -0.0198873     0.0021483    35.3778984  -9.257
##                                  Pr(>|t|)    
## (Intercept)          < 0.0000000000000002 ***
## sd_level             < 0.0000000000000002 ***
## race_cond21                       0.00239 ** 
## race_cond22               0.0000000181909 ***
## I(sd_level^2)        < 0.0000000000000002 ***
## sd_level:race_cond21      0.0000000005145 ***
## sd_level:race_cond22      0.0000000000554 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) sd_lvl rc_c21 rc_c22 I(_^2) s_:_21
## sd_level     0.000                                   
## race_cond21  0.000  0.000                            
## race_cond22  0.000  0.000 -0.500                     
## I(sd_lvl^2) -0.166  0.000  0.000  0.000              
## sd_lvl:r_21  0.000  0.000  0.000  0.000  0.000       
## sd_lvl:r_22  0.000  0.000  0.000  0.000  0.000 -0.416
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
# Post-hoc trends 
emtrends(mod2b_intent, pairwise ~ race_cond2, var = "sd_level", pbkrtest.limit = 13425)
## $emtrends
##  race_cond2 sd_level.trend      SE  df lower.CL upper.CL
##  1black             -0.212 0.00821 105   -0.229   -0.196
##  2white             -0.252 0.00814 102   -0.268   -0.236
##  3asian             -0.232 0.00823 105   -0.249   -0.216
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95 
## 
## $contrasts
##  contrast        estimate      SE    df t.ratio p.value
##  1black - 2white   0.0398 0.00383 171.2  10.383  <.0001
##  1black - 3asian   0.0199 0.00437  26.6   4.553  0.0003
##  2white - 3asian  -0.0199 0.00396  23.9  -5.024  0.0001
## 
## Degrees-of-freedom method: kenward-roger 
## P value adjustment: tukey method for comparing a family of 3 estimates

Plot the data

plot_grid2 <- ref_grid(mod2b_intent$full_model, at = list(sd_level = c(-8, -4,  0, 4, 8)))
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'pbkrtest.limit = 13425' (or larger)
## [or, globally, 'set emm_options(pbkrtest.limit = 13425)' or larger];
## but be warned that this may result in large computation time and memory use.
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'lmerTest.limit = 13425' (or larger)
## [or, globally, 'set emm_options(lmerTest.limit = 13425)' or larger];
## but be warned that this may result in large computation time and memory use.
plot_dat2 <- emmeans(plot_grid2, specs = "sd_level", by = "race_cond2")

plot_dat2 <- as.data.frame(plot_dat2)

p2 = ggplot(data = plot_dat2, aes(x = sd_level, y = emmean, color = race_cond2, ymin = asymp.LCL, ymax = asymp.UCL)) +
  geom_line(position = position_dodge(0.5)) +
  geom_point(size = 2, position = position_dodge(0.5)) +
  geom_errorbar(width = 0.5, position = position_dodge(0.5), show.legend = FALSE) +
  ylim(1,7) +
  labs(x = "Trustworthiness Dimension (SD)", y = "Intends to Harm") +
  scale_x_continuous(breaks = c(-8, -4, 0, 4, 8)) +
  scale_color_discrete(name = "", breaks = c("1black", "2white", "3asian"),
                       labels = c("Black Model", "White Model", "East Asian Model")) +
  theme(legend.position = "top",
        legend.key = element_blank())

p2

Ability Model

# Linear 
mod1_ability = mixed(ability ~ sd_level*race_cond + (sd_level*race_cond ||ResponseId) + 
                      (sd_level*race_cond ||base), 
                    data = dat, expand_re = TRUE)
## boundary (singular) fit: see help('isSingular')
summary(mod1_ability)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: ability ~ sd_level * race_cond + (1 + re1.sd_level + re1.race_cond1 +  
##     re1.race_cond2 + re1.sd_level_by_race_cond1 + re1.sd_level_by_race_cond2 ||  
##     ResponseId) + (1 + re2.sd_level + re2.race_cond1 + re2.race_cond2 +  
##     re2.sd_level_by_race_cond1 + re2.sd_level_by_race_cond2 ||      base)
##    Data: data
## 
## REML criterion at convergence: 38194.7
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.2233 -0.5095  0.0415  0.5671  5.5962 
## 
## Random effects:
##  Groups       Name                       Variance   Std.Dev.
##  ResponseId   (Intercept)                0.46253885 0.68010 
##  ResponseId.1 re1.sd_level               0.00924006 0.09613 
##  ResponseId.2 re1.race_cond1             0.00148391 0.03852 
##  ResponseId.3 re1.race_cond2             0.01020322 0.10101 
##  ResponseId.4 re1.sd_level_by_race_cond1 0.00000000 0.00000 
##  ResponseId.5 re1.sd_level_by_race_cond2 0.00067226 0.02593 
##  base         (Intercept)                0.01109775 0.10535 
##  base.1       re2.sd_level               0.00006021 0.00776 
##  base.2       re2.race_cond1             0.00000000 0.00000 
##  base.3       re2.race_cond2             0.00000000 0.00000 
##  base.4       re2.sd_level_by_race_cond1 0.00000000 0.00000 
##  base.5       re2.sd_level_by_race_cond2 0.00000000 0.00000 
##  Residual                                0.89583924 0.94649 
## Number of obs: 13425, groups:  ResponseId, 179; base, 25
## 
## Fixed effects:
##                         Estimate   Std. Error           df t value
## (Intercept)             5.070776     0.055633   183.238778  91.147
## sd_level               -0.011416     0.007491   183.221691  -1.524
## race_cond1              0.006853     0.011906   237.001094   0.576
## race_cond2             -0.074488     0.013801   235.945937  -5.397
## sd_level:race_cond1     0.003371     0.002042 12565.814999   1.650
## sd_level:race_cond2     0.012002     0.002815   235.905322   4.263
##                                 Pr(>|t|)    
## (Intercept)         < 0.0000000000000002 ***
## sd_level                          0.1293    
## race_cond1                        0.5654    
## race_cond2                   0.000000164 ***
## sd_level:race_cond1               0.0989 .  
## sd_level:race_cond2          0.000029183 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) sd_lvl rc_cn1 rc_cn2 sd_:_1
## sd_level     0.000                            
## race_cond1   0.000  0.000                     
## race_cond2   0.000  0.000 -0.406              
## sd_lvl:rc_1  0.000  0.000  0.000  0.000       
## sd_lvl:rc_2  0.000  0.000  0.000  0.000 -0.363
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
# Quadratic
mod2_ability = mixed(ability ~ sd_level + race_cond + sd_level:race_cond + I(sd_level^2) + 
                       (sd_level*race_cond ||ResponseId) + 
                       (sd_level*race_cond ||base), 
                     data = dat, expand_re = TRUE)
## boundary (singular) fit: see help('isSingular')
summary(mod2_ability)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: ability ~ sd_level + race_cond + sd_level:race_cond + I(sd_level^2) +  
##     (1 + re1.sd_level + re1.race_cond1 + re1.race_cond2 + re1.sd_level_by_race_cond1 +  
##         re1.sd_level_by_race_cond2 || ResponseId) + (1 + re2.sd_level +  
##     re2.race_cond1 + re2.race_cond2 + re2.sd_level_by_race_cond1 +  
##     re2.sd_level_by_race_cond2 || base)
##    Data: data
## 
## REML criterion at convergence: 38074.9
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.1306 -0.5074  0.0476  0.5601  5.5053 
## 
## Random effects:
##  Groups       Name                       Variance       Std.Dev.  
##  ResponseId   (Intercept)                0.462915017306 0.68037858
##  ResponseId.1 re1.sd_level               0.009245864910 0.09615542
##  ResponseId.2 re1.race_cond1             0.001609765701 0.04012189
##  ResponseId.3 re1.race_cond2             0.010362661972 0.10179716
##  ResponseId.4 re1.sd_level_by_race_cond1 0.000000000000 0.00000000
##  ResponseId.5 re1.sd_level_by_race_cond2 0.000677726521 0.02603318
##  base         (Intercept)                0.011085948265 0.10528983
##  base.1       re2.sd_level               0.000060832777 0.00779954
##  base.2       re2.race_cond1             0.000032883870 0.00573445
##  base.3       re2.race_cond2             0.000000004103 0.00006406
##  base.4       re2.sd_level_by_race_cond1 0.000000000000 0.00000000
##  base.5       re2.sd_level_by_race_cond2 0.000000000000 0.00000000
##  Residual                                0.886377105300 0.94147602
## Number of obs: 13425, groups:  ResponseId, 179; base, 25
## 
## Fixed effects:
##                          Estimate    Std. Error            df t value
## (Intercept)             4.9579794     0.0564828   194.7881133  87.779
## sd_level               -0.0114157     0.0074935   183.3066926  -1.523
## race_cond1              0.0068495     0.0119314    42.2371897   0.574
## race_cond2             -0.0744879     0.0137819   235.0199254  -5.405
## I(sd_level^2)           0.0035249     0.0003035 12540.5776310  11.614
## sd_level:race_cond1     0.0033706     0.0020314 12540.5776350   1.659
## sd_level:race_cond2     0.0120019     0.0028130   235.3676739   4.267
##                                 Pr(>|t|)    
## (Intercept)         < 0.0000000000000002 ***
## sd_level                          0.1294    
## race_cond1                        0.5690    
## race_cond2                   0.000000159 ***
## I(sd_level^2)       < 0.0000000000000002 ***
## sd_level:race_cond1               0.0971 .  
## sd_level:race_cond2          0.000028767 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) sd_lvl rc_cn1 rc_cn2 I(_^2) sd_:_1
## sd_level     0.000                                   
## race_cond1   0.000  0.000                            
## race_cond2   0.000  0.000 -0.402                     
## I(sd_lvl^2) -0.172  0.000  0.000  0.000              
## sd_lvl:rc_1  0.000  0.000  0.000  0.000  0.000       
## sd_lvl:rc_2  0.000  0.000  0.000  0.000  0.000 -0.361
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
# Post-hoc trends 
emtrends(mod2_ability, pairwise ~ race_cond, var = "sd_level", pbkrtest.limit = 13425)
## $emtrends
##  race_cond sd_level.trend      SE  df lower.CL upper.CL
##  asian          -0.007989 0.00776 205  -0.0233  0.00732
##  black           0.000643 0.00800 229  -0.0151  0.01641
##  white          -0.026732 0.00800 225  -0.0425 -0.01096
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95 
## 
## $contrasts
##  contrast      estimate      SE    df t.ratio p.value
##  asian - black -0.00863 0.00402 264.7  -2.147  0.0826
##  asian - white  0.01874 0.00402  33.9   4.661  0.0001
##  black - white  0.02737 0.00525  66.9   5.218  <.0001
## 
## Degrees-of-freedom method: kenward-roger 
## P value adjustment: tukey method for comparing a family of 3 estimates