analyse_09_pictureword_acc.R 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. library(dplyr)
  2. library(readr)
  3. library(purrr)
  4. library(tidyr)
  5. library(forcats)
  6. library(brms)
  7. library(ggdist)
  8. library(ggplot2)
  9. theme_set(theme_classic() + theme(strip.background = element_rect(fill = "white"), plot.background = element_blank()))
  10. library(patchwork)
  11. library(RColorBrewer)
  12. eff_cols <- c("#000000", brewer.pal(3, "Set1")[1:2], brewer.pal(5, "Set1")[5])
  13. cong_cols <- c("#E69F00", "#009E73")
  14. norm01 <- function(x, ...) (x-min(x, ...)) / (max(x, ...) - min(x, ...))
  15. norm01_manual <- function(x, min_x, max_x) (x-min_x) / (max_x - min_x)
  16. # import data -------------------------------------------------------------
  17. # get the stimuli's percentage of name agreement values
  18. stim <- read_csv("boss.csv", col_types = cols(perc_name_agree_denom_fq_inputs = col_number())) %>%
  19. select(filename, perc_name_agree_denom_fq_inputs) %>%
  20. rename(perc_name_agree = perc_name_agree_denom_fq_inputs)
  21. d <- file.path("raw_data", "stim-pc", "data", "pictureword") %>%
  22. list.files(pattern = "^.*\\.csv$", full.names = TRUE) %>%
  23. map_df(read_csv, col_types = cols(sex="c")) %>%
  24. filter(rt <= 1500) %>%
  25. left_join(stim, by=c("image" = "filename")) %>%
  26. mutate(
  27. prop_agree = perc_name_agree/100,
  28. pred_norm = norm01(prop_agree),
  29. cong_dev = scale(if_else(condition == "A1", 1, 0), center = TRUE, scale = FALSE)
  30. )
  31. # setup priors for RT model -----------------------------------------------
  32. priors <- c(
  33. set_prior("normal(4, 1)", class="b", coef="Intercept")
  34. )
  35. n_cores <- 7
  36. seed <- 3101
  37. n_iter <- 10000
  38. n_warmup <- 5000
  39. adapt_delta <- 0.9
  40. max_treedepth <- 10
  41. n_chains <- 5
  42. refresh <- 100
  43. f <- brmsformula(
  44. acc ~ 0 + Intercept + cong_dev * pred_norm +
  45. (cong_dev * pred_norm | subj_id) +
  46. (cong_dev | image) +
  47. (1 | string)
  48. )
  49. m_acc <- brm(
  50. formula = f,
  51. data = d,
  52. family = bernoulli("logit"),
  53. prior = priors,
  54. iter = n_iter,
  55. warmup = n_warmup,
  56. chains = n_chains,
  57. control = list(
  58. adapt_delta = adapt_delta,
  59. max_treedepth = max_treedepth
  60. ),
  61. sample_prior = "no",
  62. silent = TRUE,
  63. cores = n_cores,
  64. seed = seed,
  65. thin = 1,
  66. file = file.path("mods", "m_acc.rds"),
  67. refresh = refresh
  68. )
  69. m_draws <- as_draws_df(m_acc, variable="^b\\_", regex=TRUE) %>%
  70. select(-.chain, -.iteration, -.draw)
  71. m_draws_long <- m_draws %>%
  72. pivot_longer(cols=everything(), names_to="par", values_to="est") %>%
  73. mutate(par_lab = factor(recode(
  74. par,
  75. b_Intercept = "Intercept",
  76. b_cong_dev = "Congruency",
  77. b_pred_norm = "Predictability",
  78. `b_cong_dev:pred_norm` = "Congruency\n* Predictability"
  79. ), levels = c("Intercept", "Congruency", "Predictability", "Congruency\n* Predictability")))
  80. pl_intercept <- m_draws_long %>%
  81. filter(par == "b_Intercept") %>%
  82. ggplot(aes(est, "Intercept")) +
  83. stat_pointinterval(point_interval = "median_hdi", .width=.89) +
  84. labs(x = NULL, y = NULL, tag = "a")
  85. pl_slopes <- m_draws_long %>%
  86. filter(par != "b_Intercept") %>%
  87. mutate(par_lab = fct_rev(par_lab)) %>%
  88. ggplot(aes(est, par_lab)) +
  89. geom_vline(xintercept=0, linetype="dashed") +
  90. stat_pointinterval(point_interval = "median_hdi", .width=.89) +
  91. labs(x = "Estimate (Logits)", y = NULL) +
  92. theme(legend.position = "none")
  93. pl_coefs <- (pl_intercept / pl_slopes) +
  94. plot_layout(heights = c(1, 5))
  95. m_preds <- seq(0.1, 1, 0.001) %>%
  96. split(., ceiling(seq_along(.)/100)) %>%
  97. map_dfr(function(p) {
  98. m_draws %>%
  99. expand_grid(
  100. prop_agree = p,
  101. condition = c("Congruent", "Incongruent")
  102. ) %>%
  103. mutate(
  104. pred_norm = norm01_manual(prop_agree, min_x=min(d$prop_agree), max_x=max(d$prop_agree)),
  105. cong_dev = as.numeric(scale(if_else(condition == "Congruent", 1, 0), center = TRUE, scale = FALSE)),
  106. pred_logit = b_Intercept +
  107. cong_dev * b_cong_dev +
  108. pred_norm * b_pred_norm +
  109. cong_dev * pred_norm * `b_cong_dev:pred_norm`,
  110. pred_odds = exp(pred_logit),
  111. prob = pred_odds / (1 + pred_odds)
  112. ) %>%
  113. group_by(condition, prop_agree) %>%
  114. median_hdi(prob, .width=0.89)
  115. }) %>%
  116. mutate(
  117. perc_name_agree = prop_agree * 100,
  118. condition = factor(condition, levels = c("Congruent", "Incongruent"))
  119. )
  120. pl_preds <- m_preds %>%
  121. ggplot(aes(perc_name_agree, prob, colour=condition, fill=condition)) +
  122. geom_line(size=0.5) +
  123. geom_ribbon(aes(ymin=.lower, ymax=.upper), size=0.001, alpha=0.25) +
  124. scale_colour_manual(values = cong_cols, guide=guide_legend(nrow=1)) +
  125. scale_fill_manual(values = cong_cols, guide=guide_legend(nrow=1)) +
  126. labs(
  127. x = "Predictability (%)",
  128. y = "Probability of Correct Response",
  129. colour = "Picture-Word Congruency",
  130. fill = "Picture-Word Congruency",
  131. tag = "b"
  132. ) +
  133. scale_x_continuous(expand = expansion()) +
  134. scale_y_continuous(expand = expansion(), limits=c(NA, 1)) +
  135. theme(
  136. legend.position = c(0.95, 0.05),
  137. legend.justification = c(1, 0),
  138. legend.key.height = unit(4, "pt")
  139. )
  140. res_pl <- (pl_coefs | pl_preds) +
  141. plot_layout(widths = c(0.55, 1))
  142. ggsave(file.path("figs", "09_pictureword_acc_res.pdf"), res_pl, width=6.5, height=3)
  143. ggsave(file.path("figs", "09_pictureword_acc_res.png"), device="png", type="cairo", res_pl, width=6.5, height=3)