1- pbinom(0.6*144, 144, 0.5)[1] 0.007685257
The present project aims to rescue the replication of Experiment 1 of Todd et al. (2016, Psychological Science), which used photos of Black and White boys as primes for the categorization of objects (gun vs. toy) in a reaction time experiment. This experiment contributed to the literature on the perceptual basis of racism and stereotyping.
Specifically, the rescue will focus on attempting to replicate the results of an interaction of prime of race and speed of object categorization. For that, access to the stimuli utilized in the experiment (i.e., images of faces of boys and a set of images of objects to be categorized) was needed. In addition, the experiment was programmed in PsychoPy.
Challenges involved recreating the experimental paradigm in line with the original and analyzing the data using the same statistical techniques. Adding other controls to guarantee the high quality of the experiment (e.g., exclusion criteria) was also challenging.
Link to original study in repo
The prior replication attempt had a substantially smaller sample size (effective N=26) than the original study (N=63). This decision was based on a a priori power analysis indicating a sample size of N = 24 for 95% power. Additionally, the original study was conducted in an in-person lab setting, while the replication attempt was conducted online using Mechanical Turk. All other relevant criteria seem to be equal or comparable to the original study.
No other replication attempts of this experiment were found. Upon contact with the original author, they offered to run a parallel replication attempt at their university with an undergraduate student sample. The results of this parallel replication attempt are included in this report.
“White participants completed sequential priming tasks in which they categorized threatening and non-threatening objects (toys and guns) and words after brief presentations of Black and White children’s faces.”
The present rescue attempt will keep the same methodological paradigm and recode the original experiment in PsychoPy. Additionally, this rescue attempt will collect data online using Prolific as opposed to Mechanical Turk.
The original effect size was ηp2 = .22 which translates into an effect size of 0.53. Power analysis shows that I need 16 participants for 80% power, 20 for 90%, and 24 for 95% power. This effect size is for the 2 (race of prime: Black, White) × 2 (target object: gun, toy) repeated measures analysis of variance (ANOVA). Attaining this number of participants is easily feasible with Prolific.
Considering the initial replication attempt failed to find an effect, I will propose a sample closer to the original sample of the study, aiming for effective N = 60. According to G*Power, a sample of N = 60 would have a power of near 1 to find the original effect size.
A sensitivity power analysis with G*Power revealed that, with 60 participants, this experiment has 80% power to detect an effect size as small as 0.07.
We will recruit 66 participants to be close to the N of the original study. We added 6, which is 10% of 60 to ensure we will still have enough participants after the exclusion criteria. We will exclude non-White participants in the analysis. We will also exclude participants who have less than 60% level of accuracy. The original study excluded based on 50% accuracy or lower (chance-level), meaning that a participant who guesses every single trial might still have a reasonable chance of not being excluded. The chance of a participant reaching 60% accuracy over 144 trials is:
1- pbinom(0.6*144, 144, 0.5)[1] 0.007685257
“The primes were 12 photos of boys (6 Black, 6 White) taken from the Child Affective Facial Expression set (LoBue & Thrasher, 2015). We selected these photos using the following criteria: The faces had to be easily categorized by race, to have a neutral expression, to have no idiosyncrasies (e.g., facial scars), and to be similar in actual age (mean age for Black faces = 4.98 years; mean age for White faces = 5.01 years; p > .250). Each photo was cropped so that it included only the head and was standardized in size. The target objects were 6 gun images taken from Payne (2001) and 6 toy images (e.g., a rattle) taken from online sources. The toy images were converted to grayscale and sized to match the gun images.”
Instead of beginning with a blank screen (500 ms) like in the original article, we began with a screen that instructed participants to “Press the space bar to continue” after each trial. The rest of the procedures were the same. Participants were instructed to place their fingers on the P and Q keys on their keyboard, and told they would have to quickly press “P” when seeing a toy and “Q” when seeing a gun. After feedback from the original author, we edited visual features of the experimental paradigm to the best of our ability to match the original experiment.
“Each trial sequence began [..] followed by a face prime (200 ms), then a target object (200 ms), and finally a pattern mask (which remained on screen until participants responded). If participants did not respond within 500 ms, a message (“Please respond faster!”) appeared for 1 s. Each of the 12 face primes was paired once with each of the 12 target objects, which resulted in 144 randomly ordered experimental trials. Eight practice trials preceded the experimental trials.” After each trial, including the ones participants did not respond fast enough, participants had to press the space bar to move on to the next trial.
This replication included 12 practice trials instead of 8.
Additionally, following the recommendation in a commentary in the previous replication attempt report, we will include a cover page for the study, as recommended by the author: “This task is investigating object recognition under distracting conditions. You will be asked to quickly identify objects will being distracted by other stimuli.”
The experiment already contains built-in attention checks as it alerts the participant to pay attention if they are too slow to react to the image. Additionally, the rescue replication will exclude participants with less than 60% accuracy rate, virtually eliminating participants who do not complete the experiment in good faith. We will also exclude non-white participants, as did the original study and the 1st replication attempt.
“Before analysis, we excluded errors and RTs less than 100 ms. RTs exceeding the 500-ms deadline were excluded from analyses, and responses on those trials were treated as errors. We then subjected the remaining RTs to a log transformation (Payne, 2001); however, for interpretive ease, we report raw RTs. A 2 (race of prime: Black, White) × 2 (target object: gun, toy) repeated measures analysis of variance (ANOVA) revealed a significant interaction.” The key test will be the interaction effect of this 2 X 2 ANOVA.
We will only analyze data from people who indicated their race as White.
In the original paper, a repeated measures ANOVA yielded the following results: “A 2 (race of prime: Black, White) × 2 (target object: gun, toy) repeated measures analysis of variance (ANOVA) revealed a significant interaction, F(1, 62) = 17.21, p < .001, ηp2 = .22.”
In the first replication attempt, results of the same analysis were as follows: “One-way repeated-measures analysis of variance (ANOVA) revealed no significant interaction effect of condition on reaction times: F(1, 23) = 1.3, p = .27.”
The only difference between the original study and the replication attempt in terms of procedure is that the replication attempt was made online and the original experiment was conducted in-person.
The present rescue attempt is going to try to get closer to the original study by aiming at a sample size closer to the original. Additionally, this rescue will use Prolific as opposed to MTurk. Since evidence has shown that Profilic consistently delivers higher quality data, the differences to an in-person setting could be further reduced. We will also raise the chance-exclusion cut-off to 60%.
No difference in claims is expected to occur from the original study.
We collected data from 71 Prolific participants. We excluded 1 participant for being non-white and 12 participants due to accuracy rates compatible with chance. An additional 3 participants were excluded passively for not having valid data (i.e., people that clicked on the experiment but did not follow through with it). The effective sample size was N=55.
One important observation is that this data had to be recollected due to an error in the instructions of the experiment. No additional changes exist between the present analysis and the original methods plan.
Data was imported and wrangled into a tidy format, renaming variables for better interpretability. Categorical variables were factored and relabeled.
Loading libraries
### Load Relevant Libraries
library(tidyverse)Warning: package 'tidyverse' was built under R version 4.2.3
Warning: package 'ggplot2' was built under R version 4.2.3
Warning: package 'tidyr' was built under R version 4.2.3
Warning: package 'readr' was built under R version 4.2.3
Warning: package 'stringr' was built under R version 4.2.3
Warning: package 'lubridate' was built under R version 4.2.3
library(rstatix)Warning: package 'rstatix' was built under R version 4.2.3
library(ggplot2)
library(ggpubr)Warning: package 'ggpubr' was built under R version 4.2.3
library(lme4)Warning: package 'lme4' was built under R version 4.2.3
Warning: package 'Matrix' was built under R version 4.2.3
library(ez)Warning: package 'ez' was built under R version 4.2.3
library(ggthemes)Warning: package 'ggthemes' was built under R version 4.2.3
library(reghelper)Warning: package 'reghelper' was built under R version 4.2.3
library(apaTables)Warning: package 'apaTables' was built under R version 4.2.3
library(optimx)Warning: package 'optimx' was built under R version 4.2.3
library(forcats)
library(here)Warning: package 'here' was built under R version 4.2.3
Importing data
combined_data <- read_csv(here("data", "data_csv.csv"))New names:
• `` -> `...1`
• `...97` -> `...94`
• `...98` -> `...95`
• `...99` -> `...96`
Warning: One or more parsing issues, call `problems()` on your data frame for details,
e.g.:
dat <- vroom(...)
problems(dat)
Rows: 10577 Columns: 96
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (21): intro_key.keys, participant, date, expName, psychopyVersion, press...
dbl (65): ...1, welcome.started, welcome.stopped, intro_key.rt, intro_key.du...
lgl (10): press_space_consent.duration, practice_ready_space.duration, press...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
How many participants in the dataset?
t1 <- table(combined_data$participant)
nrow(t1)[1] 71
# OBS: this includes people who did not finish the experiment#Are there non-whites?
table(combined_data$key_resp_race_check.keys)
a b n w
1 1 1 62
non_whites <- combined_data %>%
select(participant, key_resp_race_check.keys) %>%
filter(key_resp_race_check.keys == "a"|
key_resp_race_check.keys =="b"|
key_resp_race_check.keys =="n")
non_whites# A tibble: 3 × 2
participant key_resp_race_check.keys
<chr> <chr>
1 51 a
2 24 n
3 05 b
processed_dat <- combined_data %>%
#filtering non-whites
filter(!(participant == "51" |
participant == "24"|
participant == "05"))
# N check
t2 <- table(processed_dat$participant)
nrow(t2)[1] 68
processed_dat <- processed_dat %>%
mutate(
ID = participant,
StimRace = ifelse(grepl("w", face), "White", "Black"),
StimObj = ifelse(grepl("g", object), "Gun", "Toy"),
ReactionTime = key_resp.rt,
LogRT = log(key_resp.rt),
Correct = ifelse(StimObj == "Gun" & key_resp.keys == "p" | StimObj == "Toy" & key_resp.keys == "q" ,1, 0),
too_slow = ifelse(is.na(too_slow_resp.keys), FALSE, TRUE)
) %>%
mutate(Correct = ifelse(too_slow == T, 0, Correct )) %>%
filter(!(is.na(Correct))) %>%
select(c(ID, StimRace, StimObj, ReactionTime, LogRT, Correct, too_slow))
# N check
t3 <- table(processed_dat$ID)
nrow(t3)[1] 65
3 additional passive exclusions, probably due to there not being valid data points.
Checking accuracy
acc_dat <- processed_dat %>%
group_by(ID) %>%
summarise(mean_accuracy = mean(Correct))
acc_dat# A tibble: 65 × 2
ID mean_accuracy
<chr> <dbl>
1 01 0.916
2 02 0.916
3 03 0.881
4 04 0.678
5 07 0.909
6 08 0.902
7 09 0.741
8 10 0.755
9 11 0.371
10 12 0
# ℹ 55 more rows
Excluding participants due to high likelihood of being guessing:
exclude_list <- acc_dat %>%
filter(mean_accuracy < 0.6) %>%
select(-c(mean_accuracy))
exclude_list <- c(exclude_list$ID) # N = 12 people
processed_dat <- processed_dat %>%
filter(!(ID %in% exclude_list))
# N check
t3 <- table(processed_dat$ID)
nrow(t3)[1] 54
3 people were excluded based on not meeting screener criteria (e.g., identifying as White). An additional 11 people were excluded due to accuracy rates compatible with chance level (below 60%). 3 people were passively exclude for lack of valid data points.
Filtering responses that were too slow or too fast
processed_dat <- processed_dat %>%
filter(ReactionTime > 0.1 & too_slow == F)
# N check
t4 <- table(processed_dat$ID)
nrow(t4)[1] 54
A repeated measures ANOVA will be computed to probe for the significance of the Race of Prime X Object Classification interaction. RT logs will be used as per the original study and replication attempt. Box plots were generated for visualization. Additionally, bar plots with with 95% error bars were computed using ggplot2.
# Turning into factors for ANOVA
processed_dat$ID <- as_factor(processed_dat$ID)
processed_dat$StimRace <- as_factor(processed_dat$StimRace)
processed_dat$StimObj <- as_factor(processed_dat$StimObj)
#Looking at summarized data
sum_dat <- processed_dat %>%
filter(Correct == 1) %>%
group_by(StimRace, StimObj, ID) %>%
get_summary_stats(LogRT, type = "mean_sd")
sum_dat# A tibble: 216 × 7
ID StimRace StimObj variable n mean sd
<fct> <fct> <fct> <fct> <dbl> <dbl> <dbl>
1 21 Black Toy LogRT 28 -1.35 0.293
2 04 Black Toy LogRT 20 -1.49 0.337
3 25 Black Toy LogRT 35 -1.38 0.238
4 13 Black Toy LogRT 27 -1.33 0.282
5 29 Black Toy LogRT 31 -1.04 0.194
6 64 Black Toy LogRT 30 -1.20 0.252
7 17 Black Toy LogRT 36 -1.03 0.087
8 49 Black Toy LogRT 34 -1.26 0.21
9 66 Black Toy LogRT 32 -1.37 0.219
10 26 Black Toy LogRT 29 -1.33 0.22
# ℹ 206 more rows
#Barplot with CI bars
sum_dat_plot <- processed_dat %>%
filter(Correct == 1) %>%
group_by(StimObj, StimRace) %>%
summarise(
n=n(),
MeanRT=mean(ReactionTime),
sd=sd(ReactionTime)
) %>%
mutate( se=sd/sqrt(n)) %>%
mutate( ci=se * qt((1-0.05)/2 + .5, n-1))`summarise()` has grouped output by 'StimObj'. You can override using the
`.groups` argument.
sum_dat_plot# A tibble: 4 × 7
# Groups: StimObj [2]
StimObj StimRace n MeanRT sd se ci
<fct> <fct> <int> <dbl> <dbl> <dbl> <dbl>
1 Toy Black 1598 0.281 0.0741 0.00185 0.00364
2 Toy White 1620 0.278 0.0754 0.00187 0.00367
3 Gun Black 1567 0.254 0.0748 0.00189 0.00371
4 Gun White 1549 0.258 0.0736 0.00187 0.00367
barplot_rescue <- sum_dat_plot %>%
ggplot(aes(x=StimObj, y=MeanRT, fill=StimRace)) +
geom_bar(stat = "identity", position=position_dodge()) +
geom_errorbar(aes(ymin=MeanRT-ci, ymax=MeanRT+ci), width=.2,
position=position_dodge(.9)) +
ggthemes::theme_few() +
coord_cartesian( ylim = c(0.15, 0.5)) +
scale_fill_brewer(palette="Paired") +
ggtitle( "Rescue Attempt" )
barplot_rescueRunning 2x2 repeated measures ANOVA
# ANOVA was not working due to one infinite value, so deleting this value
processed_dat <- processed_dat %>%
filter(Correct == 1) %>%
filter(is.finite(LogRT))
aov_model <- aov( data = processed_dat,
LogRT ~ StimObj*StimRace + Error(ID/(StimObj*StimRace)))
summary(aov_model)
Error: ID
Df Sum Sq Mean Sq F value Pr(>F)
StimObj 1 1.20 1.1976 0.506 0.480
StimRace 1 0.15 0.1546 0.065 0.799
StimObj:StimRace 1 2.51 2.5122 1.061 0.308
Residuals 50 118.38 2.3676
Error: ID:StimObj
Df Sum Sq Mean Sq F value Pr(>F)
StimObj 1 13.665 13.665 72.823 2.15e-11 ***
StimRace 1 0.216 0.216 1.150 0.289
StimObj:StimRace 1 0.004 0.004 0.021 0.885
Residuals 51 9.570 0.188
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Error: ID:StimRace
Df Sum Sq Mean Sq F value Pr(>F)
StimRace 1 0.0031 0.00314 0.063 0.802
StimObj:StimRace 1 0.0025 0.00254 0.051 0.822
Residuals 52 2.5707 0.04944
Error: ID:StimObj:StimRace
Df Sum Sq Mean Sq F value Pr(>F)
StimObj:StimRace 1 0.437 0.4374 3.644 0.0617 .
Residuals 53 6.362 0.1200
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Error: Within
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 6118 395.9 0.06471
Interaction is marginally significant (p = 0.06) with this model.
The original author of the study demonstrated interest in running a parallel replication attempt with an undergrad pool of participants at his institution. He collected data for N = 168 participants. In the following, I am going to analyze his data as well and include in my report and mini meta-analysis.
Importantly, this undergraduate convenience sample is not homogeneously white, as is the case with the other samples. Below I investigate the ethnic/racial composition of the sample and create a white subsample.
demo_par <- readxl::read_excel(here("data","parallel_replication_demographics.xlsx")) %>%
select(Subject, subrace, subrace_open) %>%
mutate(race_ethnicity = case_when(
subrace == 1 ~ "Asian, Asian American, or Pacific Islander",
subrace == 2 ~ "Black or African American",
subrace == 3 ~ "Latino/a/x/e or Hispanic",
subrace == 4 ~ "Native American",
subrace == 5 ~ "White or European American",
subrace == 6 ~ "Mixed or Multiracial",
subrace == 7 ~ "Middle Eastern or North African",
subrace == 8 ~ "Prefer not to respond",
TRUE ~ "Unknown"))
prop.table(table(demo_par$race_ethnicity))
Asian, Asian American, or Pacific Islander
0.48214286
Black or African American
0.04166667
Latino/a/x/e or Hispanic
0.26190476
Middle Eastern or North African
0.01785714
Mixed or Multiracial
0.02976190
Native American
0.01785714
Prefer not to respond
0.01190476
White or European American
0.13690476
Only 13% (N = 23) of the sample is white. For power purposes, I will do the main analysis with the whole sample for now, but will create a subsample and run the ANOVA for comparison.
data_par_raw <- readxl::read_excel(here("data","parallel_replication_data.xlsx"))
data_par <- data_par_raw %>%
select(Subj, race_prime, target, RT, Correct)
# N check
nrow(table(data_par$Subj))[1] 168
# Checking accuracy
acc_dat_par <- data_par %>%
group_by(Subj) %>%
summarise(mean_accuracy = mean(Correct))
hist(acc_dat_par$mean_accuracy)Exclude people with accuracy below 60%
exclude_list_par <- acc_dat_par %>%
filter(mean_accuracy < 0.6) %>%
select(-c(mean_accuracy))
exclude_list_par <- c(exclude_list_par$Subj) # N = 7 people
data_par <- data_par %>%
filter(!(Subj %in% exclude_list_par))
# N check
nrow(table(data_par$Subj))[1] 161
Filtering out responses that were too slow (> 500 ms) or too fast (< 100 ms)
data_par <- data_par %>%
filter(RT > 0.1 | RT < 500)
# N check
nrow(table(data_par$Subj))[1] 161
Preparing for analyses
# Turning into factors for ANOVA
data_par$Subj <- as_factor(data_par$Subj)
data_par$race_prime <- as_factor(data_par$race_prime)
data_par$target <- as_factor(data_par$target)
#Looking at summarized data
sum_dat_par <- data_par %>%
filter(Correct == TRUE) %>%
mutate(LogRT = log(RT)) %>%
group_by(race_prime, target, Subj) %>%
get_summary_stats(LogRT, type = "mean_sd")
sum_dat_par# A tibble: 644 × 7
Subj race_prime target variable n mean sd
<fct> <fct> <fct> <fct> <dbl> <dbl> <dbl>
1 1 black gun LogRT 36 5.81 0.2
2 2 black gun LogRT 34 5.61 0.257
3 3 black gun LogRT 33 5.45 0.242
4 4 black gun LogRT 34 5.88 0.459
5 5 black gun LogRT 35 5.29 0.358
6 6 black gun LogRT 34 5.25 0.258
7 7 black gun LogRT 35 5.29 0.258
8 8 black gun LogRT 32 5.53 0.3
9 9 black gun LogRT 35 5.72 0.299
10 10 black gun LogRT 32 5.64 0.39
# ℹ 634 more rows
Parallel replication plot
#Barplot with CI bars
sum_dat_plot_par <- data_par %>%
filter(Correct == T) %>%
group_by(race_prime, target) %>%
summarise(
n=n(),
MeanRT=mean(RT),
sd=sd(RT)
) %>%
mutate( se=sd/sqrt(n)) %>%
mutate( ci=se * qt((1-0.05)/2 + .5, n-1))`summarise()` has grouped output by 'race_prime'. You can override using the
`.groups` argument.
sum_dat_plot_par# A tibble: 4 × 7
# Groups: race_prime [2]
race_prime target n MeanRT sd se ci
<fct> <fct> <int> <dbl> <dbl> <dbl> <dbl>
1 black gun 5245 295. 239. 3.29 6.46
2 black toy 5262 335. 226. 3.11 6.10
3 white gun 5197 300. 225. 3.13 6.13
4 white toy 5304 334. 279. 3.83 7.51
barplot_par <- sum_dat_plot_par %>%
ggplot(aes(x=target, y=MeanRT, fill=race_prime)) +
geom_bar(stat = "identity", position=position_dodge()) +
geom_errorbar(aes(ymin=MeanRT-ci, ymax=MeanRT+ci), width=.2,
position=position_dodge(.9)) +
ggthemes::theme_few() +
guides(fill = F) +
coord_cartesian( ylim = c(150, 500)) +
scale_fill_brewer(palette="Paired") +
scale_x_discrete(limits = rev) +
ggtitle( "Parallel Replication Attempt" ) Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
of ggplot2 3.3.4.
barplot_parData analysis of parallel replication attempt
# log transforming
data_par <- data_par %>%
mutate(LogRT = log(RT))
# repeated measures ANOVA
aov_model_par <- aov( data = data_par,
LogRT ~ target*race_prime + Error(Subj/(target*race_prime)))
summary(aov_model_par)
Error: Subj
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 160 856.9 5.356
Error: Subj:target
Df Sum Sq Mean Sq F value Pr(>F)
target 1 92.32 92.32 267.7 <2e-16 ***
Residuals 160 55.17 0.34
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Error: Subj:race_prime
Df Sum Sq Mean Sq F value Pr(>F)
race_prime 1 0.189 0.1891 1.184 0.278
Residuals 160 25.540 0.1596
Error: Subj:target:race_prime
Df Sum Sq Mean Sq F value Pr(>F)
target:race_prime 1 0.558 0.5579 4.342 0.0388 *
Residuals 160 20.560 0.1285
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Error: Within
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 22540 3858 0.1712
Interaction is significant at the 5% level in this model.
Now considering a mixed-effects model that is more appropriate to handle unbalanced design:
# Consider this model
lmm <- lmerTest::lmer( data = processed_dat,
LogRT ~ StimObj*StimRace + (StimObj|ID))
summary(lmm)Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: LogRT ~ StimObj * StimRace + (StimObj | ID)
Data: processed_dat
REML criterion at convergence: 937.2
Scaled residuals:
Min 1Q Median 3Q Max
-4.1665 -0.6379 0.0305 0.6597 3.1209
Random effects:
Groups Name Variance Std.Dev. Corr
ID (Intercept) 0.018310 0.13532
StimObjGun 0.004088 0.06393 -0.03
Residual 0.065045 0.25504
Number of obs: 6334, groups: ID, 54
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -1.307e+00 1.951e-02 5.952e+01 -66.985 < 2e-16 ***
StimObjGun -1.106e-01 1.261e-02 9.587e+01 -8.773 6.48e-14 ***
StimRaceWhite -1.474e-02 9.007e-03 6.236e+03 -1.636 0.1019
StimObjGun:StimRaceWhite 3.337e-02 1.285e-02 6.234e+03 2.598 0.0094 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) StmObG StmRcW
StimObjGun -0.187
StimRaceWht -0.233 0.360
StmObjG:SRW 0.163 -0.509 -0.701
simple_slopes(lmm) StimObj StimRace Test Estimate Std. Error df t value Pr(>|t|) Sig.
1 Toy sstest -0.0147 0.0090 6235.5260 -1.6360 0.10188
2 Gun sstest 0.0186 0.0092 6235.4342 2.0351 0.04188 *
3 sstest Black -0.1106 0.0126 95.8714 -8.7727 6.485e-14 ***
4 sstest White -0.0772 0.0126 95.9393 -6.1249 1.991e-08 ***
In this model, we see a significant interaction of object and race of prime at the 1% level. Simple slopes analysis indicates there is an effect of race for gun, but not for toy.
OBS: A decision was made to include a random intercept and a random coefficient for StimObj (i.e., gun vs. toy) but not for StimRace or the interaction due to issues with singularity in the model.
# Consider this model
lmm_par <- lmerTest::lmer( data = data_par,
LogRT ~ target*race_prime + (target|Subj))
summary(lmm_par) Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: LogRT ~ target * race_prime + (target | Subj)
Data: data_par
REML criterion at convergence: 25514.9
Scaled residuals:
Min 1Q Median 3Q Max
-8.4531 -0.4057 0.0334 0.4459 9.1779
Random effects:
Groups Name Variance Std.Dev. Corr
Subj (Intercept) 0.038056 0.19508
targettoy 0.004833 0.06952 -0.24
Residual 0.170800 0.41328
Number of obs: 23184, groups: Subj, 161
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 5.557e+00 1.630e-02 1.793e+02 340.806 <2e-16 ***
targettoy 1.360e-01 9.432e-03 3.572e+02 14.421 <2e-16 ***
race_primewhite 1.552e-02 7.677e-03 2.286e+04 2.022 0.0432 *
targettoy:race_primewhite -1.962e-02 1.086e-02 2.286e+04 -1.807 0.0707 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) trgtty rc_prm
targettoy -0.323
race_prmwht -0.235 0.407
trgtty:rc_p 0.166 -0.576 -0.707
simple_slopes(lmm_par) target race_prime Test Estimate Std. Error df t value Pr(>|t|) Sig.
1 gun sstest 0.0155 0.0077 22859.9962 2.0219 0.0432 *
2 toy sstest -0.0041 0.0077 22859.9932 -0.5340 0.5933
3 sstest black 0.1360 0.0094 357.1676 14.4210 <2e-16 ***
4 sstest white 0.1164 0.0094 357.1677 12.3405 <2e-16 ***
-1.962e-02 / sqrt(0.038056+0.004833) [1] -0.0947384
Interaction is marginally significant in this model and simple slopes indicates an effect of race for guns.
OBS: A decision was made to include a random intercept and a random coefficient for target (i.e., gun vs. toy) but not for race_prime or the interaction due to issues with singularity in the model.
Below I investigate the effect by subsampling only white participants.
#Creating white subject list
white_subj_list <- demo_par %>%
filter(subrace == 5) %>%
select(Subject)
white_subj_list <- c(white_subj_list$Subject)
#Filtering the dataset
data_par_w <- data_par %>%
filter(Subj %in% white_subj_list)
#Running ANOVA
aov_model_par_w <- aov( data = data_par_w,
LogRT ~ target*race_prime + Error(Subj/(target*race_prime)))
summary(aov_model_par_w)
Error: Subj
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 22 108.2 4.92
Error: Subj:target
Df Sum Sq Mean Sq F value Pr(>F)
target 1 15.162 15.162 55.17 1.98e-07 ***
Residuals 22 6.046 0.275
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Error: Subj:race_prime
Df Sum Sq Mean Sq F value Pr(>F)
race_prime 1 0.0146 0.01462 0.163 0.691
Residuals 22 1.9768 0.08985
Error: Subj:target:race_prime
Df Sum Sq Mean Sq F value Pr(>F)
target:race_prime 1 0.0229 0.02285 0.203 0.657
Residuals 22 2.4776 0.11262
Error: Within
Df Sum Sq Mean Sq F value Pr(>F)
Residuals 3220 451.5 0.1402
The interaction is not significant at the 5% level a smaller sample (N=23) of white participants.
The original study does not have a plot, so I am creating one based on table results
# Computing data from table in original paper
data_barplot_original <- tibble(
MeanRT = c(296.6, 287.7, 255.8, 261.9),
sd = c(30.7, 30.7, 35.0, 37.4 ),
n = c(63, 63, 63, 63),
StimRace = c("Black", "White", "Black", "White"),
StimObj = c( "Toy", "Toy", "Gun", "Gun"),
se=sd/sqrt(n),
ci=se * qt((1-0.05)/2 + .5, n-1))
# Creating barplot
barplot_original <- data_barplot_original %>%
ggplot(aes(x=StimObj, y=MeanRT, fill=StimRace)) +
guides(fill = F) +
geom_bar(stat = "identity", position=position_dodge()) +
geom_errorbar(aes(ymin=MeanRT-ci, ymax=MeanRT+ci), width=.2,
position=position_dodge(.9)) +
ggthemes::theme_few() +
coord_cartesian( ylim = c(150, 500)) +
scale_fill_brewer(palette="Paired") +
ggtitle("Original") +
scale_x_discrete(limits = rev)
barplot_originalRecreating first replication attempt plot
#Creating dataset from project report
data_barplot_1strep <- data_frame(
MeanRT = c(435.0216, 433.6726, 449.5880, 447.5060),
StimRace = c("Black", "White", "Black", "White"),
StimObj = c( "Toy", "Toy", "Gun", "Gun"),
ci.lo = c(414.3615, 410.6880, 440.6488, 438.9164),
ci.hi = c(455.6817, 456.6572, 458.5272, 456.0956)
)Warning: `data_frame()` was deprecated in tibble 1.1.0.
ℹ Please use `tibble()` instead.
# Creating barplot
barplot_1strep <- data_barplot_1strep %>%
ggplot(aes(x=StimObj, y=MeanRT, fill=StimRace)) +
guides(fill = "none") +
geom_bar(stat = "identity", position=position_dodge()) +
geom_errorbar(aes(ymin=ci.lo, ymax=ci.hi), width=.2,
position=position_dodge(.9)) +
ggthemes::theme_few() +
coord_cartesian( ylim = c(150, 500)) +
scale_fill_brewer(palette="Paired") +
ggtitle("1st Replication") +
scale_x_discrete(limits = rev)
barplot_1strep#Arranging plots side by side
all_plots <- ggarrange(
barplot_original,
barplot_1strep,
barplot_rescue + theme(legend.position = c(0.8, 0.8)),
barplot_par,
nrow = 1,
widths = c(3, 3, 3, 3))Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
3.5.0.
ℹ Please use the `legend.position.inside` argument of `theme()` instead.
ggsave("Arranged plots.jpg", plot = all_plots,
width = 14)Saving 14 x 5 in image
knitr::include_graphics("Arranged plots.jpg")The present replication attempt found a marginally interaction effect of race of prime and reaction time of object categorization in a Prolific sample of 54 white participants between 18-35 years old. When using a more appropriate method (mixed-effects model), the interaction emerged more clearly and a significant effect of race of prime was found for the categorization of guns, but not for toys. The effect size was not as strong as observed in the original study (partial eta squared of 0.06 as opposed to 0.22).
Additionally, the author of the original study ran a parallel replication attempt with an undergrad participant pool at their institution. This experiment yielded a significant interaction of race of prime and object classification at the 5% significance level. From exploratory analysis with mixed effects models, as well as from patterns in the graph, it seems like the interaction is driven by a difference in reaction time for categorization of guns, but no difference for toys. The results of the parallel replication attempt are compatible with the results of the rescue experiment.
Interestingly, the sample of the parallel replication attempt (effective N = 161) was racially and ethnically diverse, which is different from the original study and the 1st and rescue replication attempts. Although a significant interaction was present in the full sample, it was not present when analyzing the white subset (N = 23) of the sample separately. Concerns of statistical power could explain a lack of effect in this subsample.
According to LeBel et al.’s (2018) taxonomy of replications, this study falls under a “Very Close Replication (Procedure or physical setting is different)”. In a scale of 0-1, the rating given to this replication attempt it 0.75. The effect was replicated for guns, but not for toys, and with a much smaller magnitude. Qualitatively, however, the interpretation of the finding remains similar, as in it would be reasonable to affirm that study participants reacted faster to categorize guns after seeing the face of a black boy versus after seeing the face of a white boy.
Combining across the original paper, 1st replication, rescue replication, and parallel replication what is the aggregate effect size?
library(metafor)Warning: package 'metafor' was built under R version 4.2.3
Warning: package 'metadat' was built under R version 4.2.3
#install.packages("MBESS")
library(MBESS)Warning: package 'MBESS' was built under R version 4.2.3
#install.packages("sjstats")
library(sjstats)Warning: package 'sjstats' was built under R version 4.2.3
Calculating partial eta sq with confidence intervals
## original
ci.pvaf(F.value=17.21, df.1=1, df.2=62, N=64, conf.level=.95)
## 1st replication
# calculating unreported partial eta sq based on anova variances:
0.000127/(0.000127+0.020138)
ci.pvaf(F.value=0.057, df.1=1, df.2=23, N=26, conf.level=.95)
# rescue
effectsize::eta_squared(aov_model)
ci.pvaf(F.value=3.552, df.1=1, df.2=54, N=56, conf.level=.95)
# parallel replication
effectsize::eta_squared(aov_model_par)
ci.pvaf(F.value=4.34, df.1=1, df.2=160, N=162, conf.level=.95)
# other option for ci (same results)
# apaTables::get.ci.partial.eta.squared(F.value=4.34, df1=1, df2=160, conf.level=.95)Creating dataset
d_meta <- tibble(
Study = c("Original", "1st replication", "Rescue", "Parallel"),
N = c(63, 26, 54, 161),
Effect_Size = c(0.22, 0.006, 0.06, 0.03),
ci.lo = c(0.06, 0, 0, 0),
ci.hi = c(0.37, 0.13, 0.21, 0.09)
)In this section, I aggregate results of the original study, the first replication attempt and the present rescue replication attempt.
for_meta <- d_meta %>%
mutate(se=(ci.hi-ci.lo)/(2*1.96))
mini_meta_mod <- rma(yi=Effect_Size, sei=se, slab=Study, data=for_meta)
summary(mini_meta_mod)
Random-Effects Model (k = 4; tau^2 estimator: REML)
logLik deviance AIC BIC AICc
3.2770 -6.5539 -2.5539 -4.3567 9.4461
tau^2 (estimated amount of total heterogeneity): 0.0000 (SE = 0.0010)
tau (square root of estimated tau^2 value): 0.0022
I^2 (total heterogeneity / total variability): 0.30%
H^2 (total variability / sampling variability): 1.00
Test for Heterogeneity:
Q(df = 3) = 6.5007, p-val = 0.0896
Model Results:
estimate se zval pval ci.lb ci.ub
0.0358 0.0174 2.0539 0.0400 0.0016 0.0699 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
aggregate <- tibble(Study="Aggregate", Effect_Size=mini_meta_mod$b,
ci.lo=mini_meta_mod$ci.lb, ci.hi=mini_meta_mod$ci.ub,N=sum(d_meta$N))
for_plot <- d_meta %>%
bind_rows(aggregate) %>%
mutate(Study=factor(Study, levels=c("Aggregate", "Original", "1st replication", "Rescue", "Parallel")))
ggplot(for_plot,aes(x=Study, y=Effect_Size, ymin=ci.lo, ymax=ci.hi, size=N)) +
geom_errorbar(colour='darkgray',size=.5,width=.25)+
geom_point(data=for_plot |> filter(Study!="Aggregate"))+
geom_point(data=for_plot |> filter(Study=="Aggregate"),shape=18, color="red")+
coord_flip()+
scale_size_area()+
geom_hline(yintercept=0,color="black")+
theme(legend.position = "none")+
geom_vline(xintercept = 1.5, lty=2)+
labs(y="Partial eta squared of repeated measures ANOVA", x="")Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
Results of the meta-analysis indicate an aggregate estimate of a partial eta squared of 0.036 for the interaction of race of prime and categorization of objects in predicting log reaction times. This estimate is significant at the 5% level. According to guidelines for interpreting partial eta squared (Miles & Shelvin, 2001), a partial eta squared of 0.036 is between a small (0.01) and medium (0.06) effect. Although this effect is substantially smaller than the one reported in the original study, the weight of the evidence points towards a small to medium effect that is significantly different from zero.
This rescue project aimed at investigating whether the race of a priming face image (Black vs. white) altered the speed necessary for participants to categorize toys and guns. There was some evidence of a statistically significant effect from Prolific data alone. When aggregated with data from the original study, the first replication attempt, and the parallel replication effort from the original author, the weight of the evidence pointed toward a small to medium effect, with a 95% confidence interval that did not include zero. Interestingly, the effect seemed to be present for a racially diverse sample of study participants, extrapolating from the original, the 1st replication, and the rescue attempt, which only included white participants.
One additional comment is the fact that the 1st replication attempt had very low quality data, a very small sample size and accuracy rates compatible with chance, so this data might be adding noise to the overall estimate of the aggregated effect.