Part 1: Summary & Reaction

Summary

Humiston and Wamsley (2019) aims to replicate Hu et al.'s 2015 study who found that implicit racial and gender biases could be reduced or even unlearned during sleep by using a procedure called targeted memory reactivation (TMR). This procedure aims to boost memory retention by increasing consolidation during sleep. When applied in this context, TMR is predicted to increase the effect of the counter-bias training and produce a greater reduction in implicit social biases, compared to the use of counter-bias training alone.

Given the potential real-world applications of TMR, Humiston and Wamsley sought to use the same procedure as Hu and colleagues in an attempt to replicate their findings.

In the 2015 study, participants first underwent a computerised counter-bias racial and gender training procedure, where they were instructed to press buttons to affirm certain pairings (for example, female faces with science-related words). This procedure uses uncued stimuli. Participants then began a 90 minute nap, with white noise playing in the background. Once a participant began slow-wave sleep, the experimenter would play either the race or gender cue during sleep to target and strengthen the counter-bias training memories. If participants awoke or were entering another sleep stage, these sound cues would be discontinued. Playing only one of the two sound cues during sleep allows for all participants to experience both the cued and uncued stimuli, however some participants (n = 16) will be played the race cue, and the other participants (n=15) will be played the gender cue.

Participants completed implicit bias assessments both before and after the counter-bias training procedure. They were again assessed immediately post-nap as well as one week after the nap.

Overall, Humiston and Wamsely failed to replicate the 2015 study's results. They found no evidence that TMR makes counter-bias training more effective. Instead, bias was found to be non-significantly greater for cued than for uncued stimuli.

Note, cued stimuli/condition refers to the TMR procedure, while uncued stimuli/condition refers to the counter-bias training.

Reaction

  1. It seems that the next step in this area of research would be to run another replication of the original study that follows the original study fully to discern whether the current replication is a result of a Type II error or if the original study’s conclusions are a result of a false positive. There were a few procedural differences that could have influenced the differing results: the post-nap verbal inquiry about noise was asked immediately after the nap in this study, and after the post-nap IATs in the original study. Further, the participants in the original study were compensated through course credits, whereas in the current replication, some received course credits and others received a cash payment.

  2. The logic of the rationale that the current study is not a result of a Type II error is compelling as the current study was well-powered (power of 0.9) to detect an effect size (if there was one) as reported by the original study. Further, the cueing effect that was observed is significantly different and in the opposite direction than that reported by the original study. Finally, the size of the non-significant effect found in current study is too small to have been reliably detected by either the original or current study. All this taken together suggests that the current cueing effect observed is significantly different to that reported in the original study, and is unlikely to indicate a noisy estimate of the originally-reported effect.

  3. When I was reading the article, I was excited to learn that there was a high possibility of an effective method to reduce implicit biases. This is such an important area of research, especially in this current society, so if this replication study is able to reproduce the original study's findings this would have great real-world implications to reduce biases among the public. However, once I finished reading the article I was disappointed by the lack of reproducibility and the lack of generalisability of the TMR procedure. I found the method described was convoluted and unclear.

Part 2: Verification

I obtained the open data from the (OSF Repository)[https://osf.io/fjy9a/]. First, I have to load the packages:

  • tidyverse: for dplyr and ggplot
  • haven: to read files from SPSS
  • readspss: to read files from SPSS
  • ggplot2: to create plots
  • janitor: to clean up data
  • plotrix: to calculate standard errors
  • gt: to create tables
  • ggpubr: compare means for plots
  • ggeasy: for easy ggplot functions
  • papaja: for apa theme

To load the packages onto RStudio, I have to use library() and have the package I want contained within the brackets.

library(tidyverse)
library(haven)
library(readspss) 
library(ggplot2)
library(janitor)
library(plotrix)
library(gt)
library(ggpubr)
library(ggeasy)
library(papaja)

The open data is in .sav format from SPSS. For this reason I need to use the read.sav() function from the readspss package. The study's data is read into RStudio by creating a new dataset called replicationdata using <-, which will contain all the data for only participants who have been included in the study. To put it simply, <- allows for the assignment of a value to a name, for example x <- table assigns the value table to the name x. read.sav() is a function from the readspss package that allows for a SPSS sav file to be read into a dataframe (i.e. replicationdata). The relevant SPSS sav file name is contained within quotation marks within the read.sav() function - in this case, our data file is called "Humiston & Wamsley 2019 data.sav".

I am using head() to see how the data is structured and what data is contained within the variables.

replicationdata <- read.sav("Humiston & Wamsley 2019 data.sav")

head(replicationdata)
##   ParticipantID exclude cue_presented heard_cue_report heard_cue_exit
## 1           ub3     yes           yes               no             no
## 2           ub6      no           yes               no             no
## 3           ub7      no           yes               no         unsure
## 4           ub8      no           yes               no             no
## 5           ub9      no           yes               no             no
## 6          ub10     yes           yes               no             no
##   predicted_cue     Cue_condition     Counterbias_order Sound_assignment
## 1            no gender cue played racial training first  machR and descG
## 2            no   race cue played racial training first  machR and descG
## 3            no   race cue played gender training first  machG and descR
## 4            no gender cue played racial training first  machR and descG
## 5     suspected gender cue played racial training first  machR and descG
## 6            no   race cue played gender training first  machG and descR
##   IAT1_order IAT234_order  IAT_order compensation General_1_Age General_1_Sex
## 1  EATF-SATF    SATS-EATS ES, SESESE         cash            19        Female
## 2  EATF-SATF    SATS-EATS ES, SESESE         cash            21        Female
## 3  SATF-EATF    EATS-SATS SE, ESESES         cash            21        Female
## 4  EATF-SATF    SATS-EATS ES, SESESE         cash            20        Female
## 5  SATF-EATF    EATS-SATS SE, ESESES         cash            21          Male
## 6  EATF-SATF    SATS-EATS ES, SESESE         cash            19          Male
##   General_1_Race General_1_English General_1_EnglishYrs General_1_Caffeine
## 1      Non-White               Yes                   NA                 No
## 2          White               Yes                   NA                Yes
## 3          White               Yes                   NA                Yes
## 4          White               Yes                   NA                 No
## 5          White               Yes                   NA                 No
## 6      Non-White               Yes                   NA                 No
##   General_1_CaffCups General_1_CaffHrsAgo General_1_SleepDisor
## 1               <NA>                   NA                   No
## 2                  1                    2                   No
## 3                  1                    3                   No
## 4               <NA>                   NA                   No
## 5               <NA>                   NA                  Yes
## 6               <NA>                   NA                   No
##   General_1_MentalDiso General_1_Meds                       General_1_MedList
## 1                   No            Yes DepoProvera, 200mg, once every 3 months
## 2                   No             No                                        
## 3                   No            Yes                  20 mg prozac every day
## 4                   No             No                                        
## 5                   No             No                                        
## 6                   No             No                                        
##   General_1_University General_1_UniYears          Demo_1_Ethnic
## 1    Furman University                  2 Not Hispanic or Latino
## 2    Furman University                  3 Not Hispanic or Latino
## 3    Furman University                  3 Not Hispanic or Latino
## 4               Furman                  2 Not Hispanic or Latino
## 5    Furman University                  3 Not Hispanic or Latino
## 6    Furman University                  1 Not Hispanic or Latino
##               Demo_1_Racial Demo_1_Gender Demo_1_NonParticipat
## 1 Black or African American        Female                 <NA>
## 2                     White        Female                 <NA>
## 3                     White        Female                 <NA>
## 4                     White        Female                 <NA>
## 5                     White          Male                 <NA>
## 6 Black or African American          Male                 <NA>
##              Epworth_1_Read            Epworth_1_TV          Epworth_1_Public
## 1 moderate chance of dozing   high chance of dozing   slight chance of dozing
## 2   slight chance of dozing slight chance of dozing   slight chance of dozing
## 3   slight chance of dozing slight chance of dozing       no chance of dozing
## 4   slight chance of dozing slight chance of dozing       no chance of dozing
## 5   slight chance of dozing slight chance of dozing       no chance of dozing
## 6 moderate chance of dozing slight chance of dozing moderate chance of dozing
##         Epworth_1_Passenger     Epworth_1_LyingDown   Epworth_1_Talking
## 1   slight chance of dozing   high chance of dozing no chance of dozing
## 2 moderate chance of dozing   high chance of dozing no chance of dozing
## 3   slight chance of dozing slight chance of dozing no chance of dozing
## 4   slight chance of dozing slight chance of dozing no chance of dozing
## 5       no chance of dozing     no chance of dozing no chance of dozing
## 6     high chance of dozing   high chance of dozing no chance of dozing
##             Epworth_1_Lunch   Epworth_1_Traffic Epworth_total
## 1   slight chance of dozing no chance of dozing            19
## 2       no chance of dozing no chance of dozing            16
## 3       no chance of dozing no chance of dozing            12
## 4   slight chance of dozing no chance of dozing            13
## 5       no chance of dozing no chance of dozing            10
## 6 moderate chance of dozing no chance of dozing            21
##   AlertTest_1_Concentr_1 AlertTest_1_Refresh_1
## 1                     80                    90
## 2                     80                    60
## 3                     60                    70
## 4                     60                    60
## 5                     70                    30
## 6                    100                   100
##                                                       AlertTest_1_Feel
## 1               3 - Awake, but relaxed; responsive but not fully alert
## 2 2 - Functioning at high levels, but not at peak; able to concentrate
## 3 2 - Functioning at high levels, but not at peak; able to concentrate
## 4               3 - Awake, but relaxed; responsive but not fully alert
## 5               3 - Awake, but relaxed; responsive but not fully alert
## 6                       1 - Feeling active, vital alert, or wide awake
##   AlertTest_2_Concentr_1 AlertTest_2_Refresh_1
## 1                     NA                    NA
## 2                     70                    70
## 3                     60                    60
## 4                     40                    30
## 5                     60                    30
## 6                     80                    80
##                                                       AlertTest_2_Feel
## 1                                                                 <NA>
## 2               3 - Awake, but relaxed; responsive but not fully alert
## 3 2 - Functioning at high levels, but not at peak; able to concentrate
## 4                                         4 - Somewhat foggy, let down
## 5               3 - Awake, but relaxed; responsive but not fully alert
## 6 2 - Functioning at high levels, but not at peak; able to concentrate
##   AlertTest_3_Concentr_1 AlertTest_3_Refresh_1
## 1                     90                    80
## 2                     NA                    NA
## 3                     60                    70
## 4                     40                    50
## 5                     80                    70
## 6                    100                   100
##                                                       AlertTest_3_Feel
## 1 2 - Functioning at high levels, but not at peak; able to concentrate
## 2                                                                 <NA>
## 3 2 - Functioning at high levels, but not at peak; able to concentrate
## 4               3 - Awake, but relaxed; responsive but not fully alert
## 5 2 - Functioning at high levels, but not at peak; able to concentrate
## 6                       1 - Feeling active, vital alert, or wide awake
##   AlertTest_4_Concentr_1 AlertTest_4_Refresh_1
## 1                     80                    80
## 2                     80                    90
## 3                     60                    50
## 4                     40                    30
## 5                     NA                    NA
## 6                     90                    80
##                                                       AlertTest_4_Feel
## 1 2 - Functioning at high levels, but not at peak; able to concentrate
## 2                       1 - Feeling active, vital alert, or wide awake
## 3               3 - Awake, but relaxed; responsive but not fully alert
## 4               3 - Awake, but relaxed; responsive but not fully alert
## 5                                                                 <NA>
## 6                                                                    0
##   S1_ExitQ_1_sound S1_ExitQ_1_soundaffect S1_ExitQ_2_sound S1_ExitQ_3_sound
## 1             <NA>                   <NA>             <NA>             <NA>
## 2               No                     No               No               No
## 3               No                     No               No               No
## 4               No                     No               No               No
## 5               No                     No               No               No
## 6               No                     No               No               No
##   S1_ExitQ_4_sound S1_ExitQ_4_soundaffect S1_ExitQ_5_sound
## 1             <NA>                   <NA>             <NA>
## 2               No                     No               No
## 3               No                     No               No
## 4               No                     No               No
## 5               No                     No               No
## 6               No                     No               No
##   S1_ExitQ_5_soundaffect S2_ExitQ_1_sound S2_ExitQ_1_soundaffect
## 1                   <NA>             <NA>                   <NA>
## 2                     No               No                     No
## 3                     No               No                     No
## 4                     No               No                     No
## 5                     No               No                     No
## 6                     No               No                     No
##   S2_ExitQ_2_sound S2_ExitQ_3_sound S2_ExitQ_4_sound S2_ExitQ_4_soundaffect
## 1             <NA>             <NA>             <NA>                   <NA>
## 2               No               No               No                     No
## 3               No               No               No                     No
## 4               No               No               No                     No
## 5               No               No               No                     No
## 6               No               No               No                     No
##   S2_ExitQ_5_sound S2_ExitQ_5_soundaffect Total_sleep Wake_amount NREM1_amount
## 1             <NA>                   <NA>          64          26           19
## 2               No                     No          65          25           10
## 3               No                     No          66          24            9
## 4               No                     No          80          10            5
## 5               No                     No          62          28            5
## 6               No                     No          84           6            4
##   NREM2_amount SWS_amount REM_amount SWSxREM cue_minutes baseIATcued
## 1         29.0          8          9      72        19.0  0.19620397
## 2         20.0         12         23     276         9.5  0.57544182
## 3         52.0         19          0       0        12.0  0.09911241
## 4         15.0         24         17     408        15.5  0.20577365
## 5         15.5         24         17     408        16.0  0.35314196
## 6         51.0         22          6     132        29.0 -0.21579533
##   baseIATuncued  preIATcued preIATuncued  postIATcued postIATuncued weekIATcued
## 1    -0.2653553 -0.34989445   -0.4905672 -0.192035676   -1.04192332  -0.3613492
## 2     0.6095365  0.55905291    0.2146214  0.681910146    0.46728694   0.2037737
## 3     0.6439654 -0.13380639    0.3398503  0.044634805   -0.05686262   0.4587371
## 4     1.5243562  0.51077026    0.3799023 -0.002583615    0.68243589   0.3985947
## 5     0.1310848 -0.02933191   -0.9420955 -0.245989410    0.94970369   0.9234159
## 6    -0.4344782  0.06515661   -0.1185617 -0.958083677    0.28246751  -0.3426443
##   weekIATuncued postnap_change_cued postnap_change_uncued week_change_cued
## 1     0.3829139           0.1578588            -0.5513561                0
## 2     0.6827742           0.1228572             0.2526655                0
## 3    -0.0107046           0.1784412            -0.3967129                0
## 4     0.7118729          -0.5133539             0.3025336                0
## 5     0.2021283          -0.2166575             1.8917992                0
## 6    -0.1973225          -1.0232403             0.4010292                0
##   week_change_uncued diff_biaschange_cued diff_biaschange_uncued
## 1                  0            0.5575531            -0.64826921
## 2                  0            0.3716681            -0.07323769
## 3                  0           -0.3596247             0.65466998
## 4                  0           -0.1928210             0.81248335
## 5                  0           -0.5702740            -0.07104354
## 6                  0            0.1268490            -0.23715575
##   diff_biaschange base_IAT_race base_IAT_gen pre_IAT_race pre_IAT_gen
## 1       1.2058224   -0.26535527    0.1962040  -0.49056718 -0.34989445
## 2       0.4449058    0.57544182    0.6095365   0.55905291  0.21462144
## 3      -1.0142947    0.09911241    0.6439654  -0.13380639  0.33985028
## 4      -1.0053044    1.52435622    0.2057736   0.37990232  0.51077026
## 5      -0.4992304    0.13108478    0.3531420  -0.94209553 -0.02933191
## 6       0.3640047   -0.21579533   -0.4344782   0.06515661 -0.11856168
##   post_IAT_race week_IAT_race post_IAT_gen week_IAT_gen     filter_$ cues_total
## 1    -1.0419233    -0.1920357  0.382913945   -0.3613492 Not Selected      285.0
## 2     0.6819101     0.2037737  0.467286940    0.6827742     Selected      142.5
## 3     0.0446348     0.4587371 -0.056862624   -0.0107046     Selected      180.0
## 4     0.6824359     0.7118729 -0.002583615    0.3985947     Selected      232.5
## 5     0.9497037     0.2021283 -0.245989410    0.9234159     Selected      240.0
## 6    -0.9580837     0.2824675 -0.342644325   -0.1973225 Not Selected      435.0

Since some participants have been excluded from the study, participants who were not included in the study have to be filtered out. To do this, a new dataframe called cleandata.

Note: %>% is the pipe operator used in RStudio. It allows for a sequence of calculations or code to be easily chained together. It takes the output of one statement and makes it the input of the next statement. In this case, we are taking the dataframe replicationdata and using it as the input for our next line of code - using filter() from the stats package to exclude anything that has "no" as part of its variable. This removes participants who are excluded in the study.

cleandata <- replicationdata %>%    
  filter(exclude == "no") 

To save time and make coding more streamlined, a .csv file for cleandata dataframe is created, so that we can simply load the file that only includes the relevant participants, instead of having to load the raw data then exclude/filter for the relevant participants. To do this, write_csv() is used to create a .csv file. In the brackets, the first argument defines the dataframe to be used (i.e. cleandata) and the second argument define the name for the file, contained within "" (i.e. cleandata.csv`).

write_csv(cleandata, path = "cleandata.csv")

Reproducing Table 1

I need to first reproduce Table 1 which contains all the participants' demographic information. To create Table 1, I have to first calculate all the values, as none of them were included within the open data file given.

Age average

The variable ageaverage is created using <-, where the sequence of code following <- is the assigned value for the named variable ageaverage. First, the cleandata dataframe is taken then piped (%>%) to be the input for select(). To select my needed variable, I use select() from the dplyr package. It allows for the selection of variables within a dataframe - namely the General_1_Age variable from the cleandata dataframe. I need to calculate the summary statistics for mean and standard deviations (sd) so I am using summarise() from the dplyr package. It allows for the creation of a new dataframe, with a column for each variable and a column for each of the summary statistics that are specified. = assigns a value (right side of symbol) to a name (left side of symbol). In this case, the name ageaverage is assigned the value of the mean of the variable General_1_Age that is calculated using the mean() function in dplyr. sd() calculates the standard deviation of the selected variable within the brackets.

ageaverage <- cleandata %>% 
  select(General_1_Age) %>% 
  summarise(ageaverage = mean(General_1_Age), 
          agesd = sd(General_1_Age))

ESS (Epworth Sleeping Scale) score

Calculating the values for this variable is identical to calculating Participants' ages, as seen above. The variable ESS is created using <-, where the sequence of code following <- is the assigned value for the named variable ESS. First, the cleandata dataframe is taken then piped (%>%) to be the input for select().

-select() is from the dplyr package. It allows for the selection of variables within a dataframe - namely the Epworth_total variable from the cleandata dataframe -summarise() is from the dplyr package. It allows for the creation of a new dataframe, with a column for each variable and a column for each of the summary statistics that are specified. - In this case, the summary statistics specified are mean and standard deviation (sd). - = assigns a value (right side of symbol) to a name (left side of symbol). In this case, the name ESSaverage is assigned the value of the mean of the variable General_1_Age that is calculated using the mean() function in dplyr. - sd() calculates the standard deviation of the selected variable within the brackets.

ESS <- cleandata %>% 
  select(Epworth_total) %>% 
  summarise(ESSaverage = mean(Epworth_total), 
            ESSsd = sd(Epworth_total))

SSS (Stanford Sleepiness Scale) To calculate SSS, the original values and variables from cleandata cannot be used and a new transformed variable must be created. I didn't realise this at first, so when I tried calculating the means and standard deviations in the same way as before, RStudio kept giving me errors.

SSSerror <- cleandata %>% 
  select(AlertTest_1_Feel) %>% 
  summarise(SSSaverage = mean(AlertTest_1_Feel),
            SSSsd = sd(AlertTest_1_Feel))
## Error: Problem with `summarise()` column `SSSsd`.
## ℹ `SSSsd = sd(AlertTest_1_Feel)`.
## x Calling var(x) on a factor x is defunct.
##   Use something like 'all(duplicated(x)[-1L])' to test for a constant vector.

I had a closer look at the data, and realised there were 4 variables with similar names. I tried binding the 4 variables into one and then calculating the means and standard deviations for this binded variable. I did this by first selecting the 4 variables using select() and using drop_na() to remove obversations containing a NA response. I then attempted to compile them into one variable using rbind() and used summarise() like before to calculate for the means and standard deviations for this binded variable. This method did output values, however they did not match to the ones published in the study.

SSStrial <- replicationdata %>% 
  select(AlertTest_1_Feel, 
         AlertTest_2_Feel, 
         AlertTest_3_Feel, 
         AlertTest_4_Feel) %>% 
  drop_na() %>% 
  summarise(SSStrialaverage = mean(rbind(AlertTest_1_Feel, AlertTest_2_Feel, AlertTest_3_Feel, AlertTest_4_Feel)),
             SSStrialsd = sd(rbind(AlertTest_1_Feel, AlertTest_2_Feel, AlertTest_3_Feel, AlertTest_4_Feel)))

Thus, I had a closer look at the data again and realised that the data under AlertTest_1_Feel was a mixture of numeric and character vectors. I realised I had to create a new variable that contains only numeric values in order to calculate my summary statistics. I used mutate() to create a new column "SSSvalue" to the existing cleandata dataframe. as.numeric() changes the variable "AlertTest_1_Feel" to numeric values. To do this, I need to specify what numeric values I want it changed to (levels = 1:5) and then indicating in labels = which observations that are needed to be replaced. Thus, the labels are changed to numeric values 1-5.

cleandata <- cleandata %>% 
  mutate( 
    SSSvalue = as.numeric( 
      x = AlertTest_1_Feel, 
      levels = 1:5,
      labels = c("1 - Feeling active, vital alert, or wide awake", 
      "2 - Functioning at high levels, but not at peak; able to concentrate",
      "3 - Awake, but relaxed; responsive but not fully alert",
      "4 - Somewhat foggy, let down",
      "5 - Foggy; losing interest in remaining awake; slowed down"),
      exclude = NA
    )
  )

Now that I've changed my SSS variable to numeric values, I can now use the same method I previously used to calculate the mean and standard deviation.

SSS <- cleandata %>% 
  select(SSSvalue) %>% 
  summarise(SSSaverage = mean(SSSvalue), 
            SSSsd = sd(SSSvalue))

Baseline Implicit Bias

Baseline Implicit Bias is the combination of the baseline implicit biases scores of both the racial and gender IAT. Thus, to calculate the mean and standard deviation for Baseline Implicit Bias, the method will be similar to what I've done before but I'll be selecting two variables (base_IAT_race and base_IAT_gen) using select() and using rbind() to bind together the race and gender baseline IAT values to calculate the mean and standard deviation for this binded value.

BIB <- cleandata %>% 
  select( 
    base_IAT_race,
    base_IAT_gen) %>% 
  summarise( 
    BIBaverage = mean(rbind(base_IAT_race, base_IAT_gen)), 
    BIBsd = sd(rbind(base_IAT_race, base_IAT_gen))
            )

Prenap Implicit Bias

Similar to Baseline Implicit Bias, Prenap Implicit Bias is the combination of the prenap implicit biases scores of both the racial and gender IAT. Thus, the method will be similar to before, except I'll be using the two variables pre_IAT_race and pre_IAT_gen.

PrenapIB <- cleandata %>% 
  select( 
    pre_IAT_race,
    pre_IAT_gen) %>% 
  summarise( 
    PrenapIBaverage = mean(
      rbind(pre_IAT_race, pre_IAT_gen)
      ),
    PrenapIBsd = sd( 
      rbind(pre_IAT_race, pre_IAT_gen))
            )

Postnap implicit bias

Similar to Baseline Implicit Bias, Postnap Implicit Bias is the combination of the postnap implicit biases scores of both the racial and gender IAT. The method will be similar to before, except I'll be using the two variables post_IAT_race and post_IAT_gen.

PostnapIB <- cleandata %>% 
  select( 
    post_IAT_race,
    post_IAT_gen) %>% 
  summarise( 
    PostnapIBaverage = mean(
      rbind( 
        post_IAT_race,
        post_IAT_gen
      )),
    PostnapIBsd = sd( 
      rbind(
        post_IAT_race,
        post_IAT_gen
      ))
  )

One-week delay implicit bias

Similar to Baseline Implicit Bias, One-week Delay Implicit Bias is the combination of the implicit biases scores of both the racial and gender IAT after a one-week delay. The method will be similar to before, except I'll be using the two variables week_IAT_race and week_IAT_gen.

OWDIB <- cleandata %>% 
  select( 
    week_IAT_race,
    week_IAT_gen) %>% 
  summarise( 
    OWDIBaverage = mean(
      rbind( 
        week_IAT_race,
        week_IAT_gen
      )
    ),
    OWDIBsd = sd( 
      rbind(
        week_IAT_race,
        week_IAT_gen
      )
    )
  )

Average sex

The table has average sex displayed as a percentage of males. Thus, I'm creating a new variable Male and using select() to choose the variable for sex. tally() counts how many "male" values are observed in the variable General_1_Sex. I then create a new variable Male_percentage that is the percentage of males in the sample by fractioning out of 31. It is fractioned out of 31 as the cleandata data has 31 participants.

Male <- cleandata %>% 
  select(General_1_Sex) %>% 
  tally(General_1_Sex == "Male") 

Male_percentage <- Male/31 

print(Male_percentage)
##          n
## 1 0.483871

Average Cue played during nap (% racial cue)

I will use a similar method as above to calculate the percentage of racial cues during the nap. I create a new variable Napcue by first selecting my needed variable using select(). I then use tally() to count how many "race cue played" observations are within the variable "Cue_condition". I use the newly-made Napcue variable to create a percentage by fractioning out of 31. Again, it is fractioned out of 31 as the cleandata data set has 31 participants.

Napcue <- cleandata %>% 
  select(Cue_condition) %>% 
  tally(Cue_condition == "race cue played") 

racialcue_perentage <- Napcue/31 

print(racialcue_perentage)
##           n
## 1 0.5483871

Creating Table 1

Now that I've calculated all the variables required, I can now create the table. After doing some research, there were three main packages for creating a table: kableExtra(), magick() and gt().

I decided to go with gt() because it seemed to produce the cleanest table. If it wasn't what I wanted, then I would then try kableExtra(), and then magick().

I wasn't sure how to input the information, but I decided to just create a new dataframe called table1 using the values that were reproduced from earlier. To create a data frame, I used tibble(). Within the brackets, I have to specify what each column will be named and then within c() I specify what data will be contained within each column.

table1 <- tibble(
  Characteristics = c("Age (yrs)", "ESS", "SSS", "Baseline implicit bias", "Prenap implicit bias", "Postnap implicit bias", "One-week delay implicit bias", "Sex (% male)", "Cue played during nap (% racial cue)"),
  Mean = c(19.5, 15.3, 2.81, 0.557, 0.257, 0.278, 0.399, 0.484, 0.548),
  SD = c(1.23, 2.83, 0.749, 0.406, 0.478, 0.459, 0.425, NA, NA)
)

I now create my table using gt(). I first have to specify what dataframe I'm using then using the pipe operator %>% to use that as my input for the gt()package. tab_header is from the gt() package and adds a table header to the gt() table. This function allows for a title and a subtitle so I have to specify that I'm creating a title. The title text is placed in quotation marks.

table1 %>% 
  gt() %>% 
  tab_header(
title = "Participant characteristics")
Participant characteristics
Characteristics Mean SD
Age (yrs) 19.500 1.230
ESS 15.300 2.830
SSS 2.810 0.749
Baseline implicit bias 0.557 0.406
Prenap implicit bias 0.257 0.478
Postnap implicit bias 0.278 0.459
One-week delay implicit bias 0.399 0.425
Sex (% male) 0.484 NA
Cue played during nap (% racial cue) 0.548 NA

After some feedback from my learning logs and collaboration with my group members, I was able to create a new dataframe that did not require me to manually input values. The format to do this is dataframe$variable - for example, if I want to take the prenap implicit bias mean I first specify the dataframe it is coming from (i.e. PrenapIB) and then the variable itself (i.e. PrenapIBsd). In the designated format, the prenap implicit bias mean will look like this: PrenapIB$PrenapIBsd. This reduces the possibility of a mistyped numerical value.

table1.2 <- tibble( #3 columns
  Characteristics = c("Age (yrs)", "ESS", "SSS", "Baseline implicit bias", "Prenap implicit bias", "Postnap implicit bias", "One-week delay implicit bias", "Sex (% male)", "Cue played during nap (% racial cue)"), #label
  Mean = c(ageaverage$ageaverage, ESS$ESSaverage, SSS$SSSaverage, BIB$BIBaverage, PrenapIB$PrenapIBaverage, PostnapIB$PostnapIBaverage, OWDIB$OWDIBaverage, Male_percentage$n, racialcue_perentage$n), 
  SD = c(ageaverage$agesd, ESS$ESSsd, SSS$SSSsd, BIB$BIBsd, PrenapIB$PrenapIBsd, PostnapIB$PostnapIBsd, OWDIB$OWDIBsd, NA, NA)
)

I also improved the formatting of the Table by using md() from the gt() package. It allows for formatting of text so I can use bolded fonts. To format values to output to 2 decimal places as is seen in the original paper, I used fmt_number() and decimals = from gt() package which controls the formatting of numeric values.

columns = specifies how to format the columns. vars is similar to select() in that it selects the variables that are needed. Combined, these two arguments specify that I want mean and sd as my columns.

To add a source note for the table footer, I used tab_source_note(). To remove the first column label "characteristics", I used cols_label. Characteristics = " " specifies that I want a blank space to replace the "Characteristics" label.

table1.2 %>% 
  gt() %>% 
  tab_header(title = md("**Table 1. Participant characteristics.**")) %>% 
  fmt_number(columns = vars(Mean, SD), 
             decimals = 2) %>% 
  tab_source_note(source_note = "Implicit bias values are the average of D600 score for each timepoint") %>%  
  cols_label(Characteristics = " ")
Table 1. Participant characteristics.
Mean SD
Age (yrs) 19.55 1.23
ESS 15.29 2.83
SSS 2.81 0.75
Baseline implicit bias 0.56 0.41
Prenap implicit bias 0.26 0.48
Postnap implicit bias 0.28 0.46
One-week delay implicit bias 0.40 0.43
Sex (% male) 0.48 NA
Cue played during nap (% racial cue) 0.55 NA
Implicit bias values are the average of D600 score for each timepoint

Reproducing Table 2

Table 2 displays the means and standard deviations for the race and gender implicit bias scores at baseline and prenap. These values need to be calculated as the open data file did not contain this information.

I first attempted to do this by manually and separately calculating each variable. For example, to calculate the mean and SD of the baseline Race bias, I created new data new data BaselineRace from cleandata (the dataset without the excluded participants). I used the select() function to select only the variable "base_IAT_race" from cleandata. Then, using the summarise() function I claculated the mean and SD for the selected variable.

BaselineRace <- cleandata %>% 
  select(base_IAT_race) %>% 
  summarise(BaselineRaceMean = mean(base_IAT_race), BaselineRaceSD = sd(base_IAT_race)) 

I followed that method for all four data variables, but one of my group members, Julia, showed our group a way to clean up the data and get the same output in a more efficient way: she created a new data set called implicitbiaslevels using <- and selected the 4 variables base_IAT_race, base_IAT_gen, pre_IAT_race, pre_IAT_gen from the cleandata dataset using the select() function. Then, she calculated the means and standard deviations for all those variables using the summarise() function. She captured and calculatesd all the means and SDs of each variable that contains "IAT" within its variable name using contains("IAT") and listed the calculated means and sds for each variable under the label "mean" and "sd" using the list() function. Now the data "implicitbiaslevels" data has the means and SDs for each of the variables previously selected, instead of having to separately code for each mean and SD needed and then having to create a new dataframe.

implicitbiaslevels <- cleandata %>% 
  select(base_IAT_race, base_IAT_gen, pre_IAT_race, pre_IAT_gen) 

implicitbiaslevels <- implicitbiaslevels %>% 
  summarise(across(contains("IAT"), list(mean = mean, sd = sd))) 

I wanted to see if this new method of coding that Julia used was able to be outputted into a table without having to create a new data frame. I hoped that this simplified code could be used to quickly and simply recreate the table. I used the same gt() package as was used for Table 1.

As was seen in Table 1, tab_header() is used to specify the table title and tab_source_note() creates a source note in the table footer. fmt_number() is used to format number in gt(). The decimals = argument formats values to 2 decimal places and vars() select which variables are to be used for each column.

However, Table 2 is different to Table 1 in that this table has grouped columns and grouped rows. I attempted to format the columns by using tab_spanner(). The label = argument specifies the spanner column label while the columns = argument specifies what variables are to be placed underneath the spanner column label. In a similar way, I attempted to format the rows by using tab_row_group(). The label = argument specifies what heading I want for this grouped row and rows = specifies how many rows I want in this row group.

However, this method kept giving me errors so I had to try another method.

implicitbiaslevels %>% 
  gt() %>% 
  tab_header(
    title = "Table 2: Race and Gender Implicit Bias Levels") %>% 
  tab_source_note("Implicit bias values are the average D600 score for each timepoint") %>% 
  fmt_number(columns = vars(base_IAT_race_mean, pre_IAT_race_mean,  base_IAT_race_sd, pre_IAT_race_sd), 
             decimals = 2) %>% 
  tab_spanner(
    label = "Baseline", 
    columns = c(implicitbiaslevels$base_IAT_race_mean, implicitbiaslevels$base_IAT_race_sd) 
  ) %>% 
  tab_spanner(
    label = "Prenap", 
    columns = c(implicitbiaslevels$pre_IAT_race_mean, implicitbiaslevels$pre_IAT_race_sd) 
  ) %>% 
  tab_row_group( 
    label = "Race", 
    rows = 1
  ) %>% 
  tab_row_group(
    label = "Gender", 
    rows = 2 
  ) 
## Error: Must subset columns with a valid subscript vector.
## x Can't convert from <double> to <integer> due to loss of precision.

Since I was having so much trouble formatting my columns and values according to the original data frame implicitbiaslevels, a new data frame had to be created that would suit Table 2's formatting. I first tried creating a new data frame like below and using it as the input for the table code used above. The only difference between the table code below and the one above is the data frame input and the variables I chose for my columns and rows.

Changing the dataframe created a table. However, there were several issues with this table - the row values are not in line with row labels and the column labels need to be renamed.

table2 <- tibble(
  mean1 = c(0.6186929, 0.4943818),
  mean2 = c(0.2023364, 0.3109984),
  SD1 = c(0.4423884, 0.36228),
  SD2 = c(0.5633004, 0.3748071))
table2 %>% 
  gt() %>% 
  tab_header(
    title = "Table 2: Race and Gender Implicit Bias Levels") %>% 
  tab_source_note("Implicit bias values are the average D600 score for each timepoint") %>% 
  fmt_number(columns = vars(mean1, mean2,  SD1, SD2), 
             decimals = 2) %>% 
  tab_spanner(
    label = "Baseline", 
    columns = c(mean1, SD1)
  ) %>% 
  tab_spanner(
    label = "Prenap",
    columns = c(mean2, SD2)
  ) %>% 
  tab_row_group(
    label = "Race", 
    rows = 1  
  ) %>% 
  tab_row_group(
    label = "Gender",
    rows = 2
  ) 
Table 2: Race and Gender Implicit Bias Levels
Baseline Prenap
mean1 SD1 mean2 SD2
Gender
0.49 0.36 0.31 0.37
Race
0.62 0.44 0.20 0.56
Implicit bias values are the average D600 score for each timepoint

After collaboration with the group, we were able to resolve this issue. By adding a column in the dataframe that specifies the row labels, a nicely-formatted table can be created. We created a new dataframe including the column for the row labels and also cleaned up our data by inputting our values in the dataframe$variable format.

table2label <- tibble(
  label = c("Race", "Gender"), 
  mean1 = c(implicitbiaslevels$base_IAT_race_mean, implicitbiaslevels$base_IAT_gen_mean),
  mean2 = c(implicitbiaslevels$pre_IAT_race_mean, implicitbiaslevels$pre_IAT_gen_mean),
  SD1 = c(implicitbiaslevels$base_IAT_race_sd, implicitbiaslevels$base_IAT_gen_sd),
  SD2 = c(implicitbiaslevels$pre_IAT_race_sd, implicitbiaslevels$pre_IAT_gen_sd))

To improve the formatting of Table 2, the tab_row_group() function is removed so that the row labels and values can be in line with each other. Further, to change the column labels we used cols_label() and to use the bold font on our column labels and table title we used md() from the gt() package.

table2label %>% 
  gt() %>% 
  tab_header(
    title = md("**Table 2. Race and gender implicit bias levels**")) %>% 
  tab_source_note("Implicit bias values are the average D600 score for each timepoint") %>% 
  fmt_number(columns = vars(mean1, mean2,  SD1, SD2), 
             decimals = 2) %>% 
  tab_spanner(
    label = md("**Baseline**"), 
    columns = c(mean1, SD1) 
  ) %>% 
  tab_spanner(
    label = md("**Prenap**"), 
    columns = c(mean2, SD2) 
  ) %>% 
  cols_label(mean1 = "Mean", mean2 = "Mean", SD1 = "SD", SD2 = "SD", label = " ") 
Table 2. Race and gender implicit bias levels
Baseline Prenap
Mean SD Mean SD
Race 0.62 0.44 0.20 0.56
Gender 0.49 0.36 0.31 0.37
Implicit bias values are the average D600 score for each timepoint

Reproducing Table 3

After finally understanding the basics of the gt() package, reproducing Table 3 and 4 was relatively simple.

Table 3 contains the means and standard deviations of implicit bias levels by cued and uncued conditions, over 4 timepoints. The calculations for the summary statistics and the formatting for the table is very similar to Table 2.

Calculating the means and standard deviations

I first attempted calculating the means and standard deviations for the cued IATs only. The process to calculate this is similar to how I calculated the implicit bias levels for Table 2. I created a new variable cued, using select() to select the 4 cued data variables. To calculate the means and standard deviations of all of these variables, I used a combination of summarise() and across(contains()). This captures and calculates the means and standard deviations of each variable that contains "IAT" within its variable name. list() calculates the means and standard deviation for each variable under the label "mean" and "sd".

Now the data "cued" has the means and standard deviations for each of the variables previously selected, instead of having to separately code for each mean and SD needed and then having to create a new dataframe.

cued <- cleandata %>% 
  select(baseIATcued, preIATcued, postIATcued, weekIATcued)

cued <- cued %>% 
  summarise(across(contains("IAT"), list(mean = mean, sd = sd))) 

After checking that this simplified code worked, I decided to tried calculating all the cued and uncued conditions together. I adjusted the above code by creating a new variable cued_uncued and selecting all 8 variables - both the cued and uncued variables at all 4 timepoints.

cued_uncued <- cleandata %>%  
  select(baseIATcued, preIATcued, postIATcued, weekIATcued,
         baseIATuncued, preIATuncued, postIATuncued, weekIATuncued)

cued_uncued <- cued_uncued %>% 
  summarise(across(contains("IAT"), list(mean = mean, sd = sd))) 

Creating the data frame for the table

After calculating all the means and standard deviations for the cued and uncued conditions, I had to create a new dataframe with the calculated values from "cued_uncued":

table3 <- tibble(
  label = c("Baseline", "Prenap", "Postnap", "1-week delay"),
  mean1 = c(0.518, 0.211, 0.307, 0.4),
  mean2 = c(0.595, 0.302, 0.249, 0.399),
  SD1 = c(0.363, 0.514, 0.445, 0.387),
  SD2 = c(0.447, 0.442, 0.478, 0.467)
)

Formatting the table

Using gt(), Table 3 is created.

table3 %>% 
  gt() %>% 
  tab_header(
    title = md("**Table 3. Implicit bias levels by condition**")) %>% 
  tab_source_note("Implicit bias values are the average D600 score for each timepoint") %>% 
  fmt_number(columns = vars(mean1, mean2,  SD1, SD2), decimals = 2) %>% 
  tab_spanner( 
    label = "Cued", 
    columns = c(mean1, SD1) 
    ) %>% 
  tab_spanner(
    label = "Uncued", 
    columns = c(mean2, SD2) 
  ) %>% 
  cols_label(mean1 = "Mean", mean2 = "Mean", SD1 = "SD", SD2 = "SD", label = " ") 
Table 3. Implicit bias levels by condition
Cued Uncued
Mean SD Mean SD
Baseline 0.52 0.36 0.59 0.45
Prenap 0.21 0.51 0.30 0.44
Postnap 0.31 0.45 0.25 0.48
1-week delay 0.40 0.39 0.40 0.47
Implicit bias values are the average D600 score for each timepoint

Reproducing Table 4

Reproducing Table 4 required more trial-and-error and research than I had originally anticipated. Table 4 requires us to calculate the number of responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for 1 participant as they did not hear the sound cue on the final exit questionnaire.

** Calculating the needed values **

I first calculated the number of people who said "no"" and "maybe" in the verbal report using:

  • select() to select the variable from my "cleandata" dataset, and
  • tally() to count the number of "no" / "maybe" responses in the selected variable.
  • glimpse() to check whether the calculated value matches the value seen in the original paper
report_no <- cleandata %>% 
  select(heard_cue_report) %>% 
  tally(heard_cue_report == "no")

report_maybe <- cleandata %>% 
  select(heard_cue_report) %>% 
  tally(heard_cue_report == "maybe, unsure, unclear")

glimpse(report_maybe)
## Rows: 1
## Columns: 1
## $ n <int> 2
glimpse(report_no)
## Rows: 1
## Columns: 1
## $ n <int> 28

I then tried to add the two calculated variables together using sum() but it kept giving me the error: "Error: Must subset columns with a valid subscript vector. x Subscript has the wrong type data.frame<n:integer>. ℹ It must be numeric or character.".

report <- cleandata %>% 
  select(report_no, report_maybe) %>% 
  sum(c(report_no, report_maybe))
## Error: Must subset columns with a valid subscript vector.
## x Subscript has the wrong type `data.frame<n:integer>`.
## ℹ It must be numeric or character.

Because of this error, I thought the variables were integers so I tried to convert them to numeric using as.numeric().

report_no <- as.numeric(as.integer(report_no))
report_maybe <- as.numeric(as.integer(report_maybe))

I used typeof() to determine what category the above variables are. It outputted as "double" and after some researching on Google, I realised that a "double" output means it is a numeric value.

typeof(report_maybe)
## [1] "double"
typeof(report_no)
## [1] "double"

I tried using the unlist() function because I read online that the error might be because the code is only temporary, and that the unlist() function makes the code permanent. Again, I used typeof() to check if it's still returning as a numeric function.

report_maybe <- as.numeric(unlist(report_maybe))
report_no <- as.numeric(unlist(report_no))
typeof(report_maybe) 
## [1] "double"

Now, I tried to use sum() again to calculate the total, hoping the error doesn't pop up, but now it's giving a different error:

report_total <- cleandata %>% 
  select(report_no, report_maybe) %>% 
      sum(report_no, report_maybe)
## Error in FUN(X[[i]], ...): only defined on a data frame with all numeric-alike variables

I then decided to just manually add the data using c() which combines the arguments within the brackets.

report_total <- c(2, 28) 
sum(report_total)
## [1] 30

Now, I had to calculate the data for the exit questionnaire. I calculated the total number of responses for the exit questionnaire by manually adding the data using c().

exit_total <- c(0, 29) 
sum(exit_total)
## [1] 29

When calculating the responses for the exit questionnaire, I finally realised that I had to exclude a participant because of their incomplete response because I kept getting an incorrect value of 29, instead of 28.

exit_no <- cleandata %>% 
  select(heard_cue_exit) %>% 
  tally(heard_cue_exit == "no")

exit_maybe <- cleandata %>% 
  select(heard_cue_exit) %>% 
  tally(heard_cue_exit == "unsure")

glimpse(exit_no)
## Rows: 1
## Columns: 1
## $ n <int> 29
glimpse(exit_maybe) 
## Rows: 1
## Columns: 1
## $ n <int> 2

Thus, I started over from the beginning and created a new dataframe without the participant who had incomplete response. I used na.omit() to remove the row with the incomplete response.

soundcuereporting <- cleandata %>% 
  select(heard_cue_exit, heard_cue_report) %>% 
  na.omit() 

I then recalculated Table 4's data without the omitted participant. This gave me the correct number of responses.

report_no <- soundcuereporting %>% 
  select(heard_cue_report) %>% 
  tally(heard_cue_report == "no")

report_maybe <- soundcuereporting %>% 
  select(heard_cue_report) %>% 
  tally(heard_cue_report == "maybe, unsure, unclear")

glimpse(report_maybe)
## Rows: 1
## Columns: 1
## $ n <int> 2
glimpse(report_no)
## Rows: 1
## Columns: 1
## $ n <int> 28
exit_no <- soundcuereporting %>% 
  select(heard_cue_exit) %>% 
  tally(heard_cue_exit == "no")

exit_maybe <- soundcuereporting %>% 
  select(heard_cue_exit) %>% 
  tally(heard_cue_exit == "unsure")

glimpse(exit_no)
## Rows: 1
## Columns: 1
## $ n <int> 28
glimpse(exit_maybe) 
## Rows: 1
## Columns: 1
## $ n <int> 2

I then realised that the values I had calculated so far were actually for the "Total" columns and not for the cells in the middle of the table. Thus, this code below calculates for the cells in the middle of the table. I used filter() to consider participants with the specified responses in both exit questionnaire and verbal report. To calculate the number of variables left after filtering, I used summarise(n=n()). This provides the number of responses in the given variable. glimpse() allowed me to check if these values are correct.

exitno_reportno <- soundcuereporting %>% 
  filter(heard_cue_exit == "no", heard_cue_report == "no") %>% 
  summarise(n=n()) 

exitno_reportmaybe <- soundcuereporting %>% 
  filter(heard_cue_exit == "no", heard_cue_report == "maybe, unsure, unclear") %>% 
  summarise(n=n())

exitmaybe_reportno <- soundcuereporting %>% 
  filter(heard_cue_exit == "unsure", heard_cue_report == "no") %>% 
  summarise(n=n())

exitmaybe_reportmaybe <- soundcuereporting %>% 
  filter(heard_cue_exit == "unsure", heard_cue_report == "maybe, unsure, unclear") %>% 
  summarise(n=n())

glimpse(exitno_reportno)
## Rows: 1
## Columns: 1
## $ n <int> 26
glimpse(exitno_reportmaybe) 
## Rows: 1
## Columns: 1
## $ n <int> 2
glimpse(exitmaybe_reportno) 
## Rows: 1
## Columns: 1
## $ n <int> 2
glimpse(exitmaybe_reportmaybe) 
## Rows: 1
## Columns: 1
## $ n <int> 0

I also calculated the total participants overall using summarise(n=n()).

soundcuereporting_total <- soundcuereporting %>% 
  summarise(n=n())

** Creating the dataframe for the table**

Now that all the variables have been calculated, I put the variables into an appropriately formatted dataframe:

table4 <- tibble(
  label = c("No", "Maybe", "Total"),
  no = c(26, 2, 28),
  maybe = c(2, 0, 2),
  total = c(28, 2, 30)
)

** Creating the table **

I created a table using the gt() package, using the same functions as I used for Tables 1-3 but the formatting did not output right.The row order did not match, and there was a double-line located in the middle of the table.

table4 %>% 
  gt() %>% 
  tab_header(
    title = "Table 4. Sound cue reporting. ") %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = vars(no, maybe, total)) %>%  
  tab_spanner( 
    label = "Reported Hearing Cue on Verbal Report?", 
    columns = c(no, maybe, total) 
    ) %>% 
  tab_row_group(
    label = "Reported Hearing Cue on Exit Questionnaire?", 
    rows = 3 
  )
Table 4. Sound cue reporting.
label Reported Hearing Cue on Verbal Report?
no maybe total
Reported Hearing Cue on Exit Questionnaire?
Total 28.00 2.00 30.00
No 26.00 2.00 28.00
Maybe 2.00 0.00 2.00
Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.

I tried to change up the formatting by adding column labels using cols_label() in order to change the column labels, but it didn't seem to change anything.

table4 %>% 
  gt() %>% 
  tab_header(
    title = "Table 4. Sound cue reporting. ") %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = vars(no, maybe,  total)) %>% 
  tab_spanner( 
    label = "Reported Hearing Cue on Verbal Report?", #Spanner column label 
    columns = c(no, maybe, total)
    ) %>% 
  tab_row_group(
    label = "Reported Hearing Cue on Exit Questionnaire?",
    rows = 3) %>% 
  cols_label(no = "No", maybe = "Maybe", total = "Total", label = " ")
Table 4. Sound cue reporting.
Reported Hearing Cue on Verbal Report?
No Maybe Total
Reported Hearing Cue on Exit Questionnaire?
Total 28.00 2.00 30.00
No 26.00 2.00 28.00
Maybe 2.00 0.00 2.00
Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.

I thought it might be an issue with the dataframe used, so I decided to make a new dataframe. I modified the dataframe by adding a column for the row labels.

table4_ <- tibble(
  label = c("label", "No", "Maybe", "Total"),
  no = c("No", 26, 2, 28),
  maybe = c("Maybe", 2, 0, 2),
  total = c("Total", 28, 2, 30)
)

I used the same code to create the table but it kept giving me an error: "The fmt_number() function can only be used on columns with numeric data". This is very likely due to the added characters I added in the new dataframe.

table4_ %>% 
  gt() %>% 
  tab_header(
    title = "Table 4. Sound cue reporting. ") %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = vars(no, maybe,  total)) %>% 
  tab_spanner( 
    label = "Reported Hearing Cue on Verbal Report?", #Spanner column label 
    columns = c(no, maybe, total)
    ) %>% 
  tab_row_group(
    label = "Reported Hearing Cue on Exit Questionnaire?",
    rows = 3
  ) %>% 
  cols_label(no = "No", maybe = "Maybe", total = "Total", label = " ")
## Error: The `fmt_number()` function can only be used on `columns` with numeric data

I decided to go back to the original dataframe, but changed the tab_row_group() function to tab_stubhead(), hoping that it would change the weird ordering of the rows. It did change it and now the table looks similar to the original paper, but the tab stubhead label for "Reported Hearing Cue on Exit Questionnaire?" is not appearing.

table4 %>% 
  gt() %>% 
  tab_header(
    title = "Table 4. Sound cue reporting. ") %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = c(no, maybe,  total)) %>% 
  tab_spanner( 
    label = "Reported Hearing Cue on Verbal Report?", #Spanner column label 
    columns = c(no, maybe, total)
    ) %>% 
  tab_stubhead(
    label = "Reported Hearing Cue on Exit Questionnaire?"
  ) %>% 
  cols_label(no = "No", maybe = "Maybe", total = "Total", label = " ")
Table 4. Sound cue reporting.
Reported Hearing Cue on Verbal Report?
No Maybe Total
No 26.00 2.00 28.00
Maybe 2.00 0.00 2.00
Total 28.00 2.00 30.00
Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.

By adding rowname_col = "label", I was able to add the tab stubhead label.

table4 %>% 
  gt(rowname_col = "label") %>% 
  tab_header(
    title = "Table 4. Sound cue reporting. ") %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = c(no, maybe,  total)) %>% 
  tab_spanner( 
    label = "Reported Hearing Cue on Verbal Report?", 
    columns = c(no, maybe, total)
    ) %>% 
  tab_stubhead(label = "Reported Hearing Cue on Exit Questionnaire?"
  ) %>% 
  cols_label(no = "No", maybe = "Maybe", total = "Total", label = " ")
Table 4. Sound cue reporting.
Reported Hearing Cue on Exit Questionnaire? Reported Hearing Cue on Verbal Report?
No Maybe Total
No 26.00 2.00 28.00
Maybe 2.00 0.00 2.00
Total 28.00 2.00 30.00
Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.

I then used the md() function to change the aesthetics of the headings (e.g. bolded, italics) but it does not alter the format of the table. I also added decimals = 0 to the fmt_number column so that there were no decimals showing.

table4 %>% 
  gt(rowname_col = "label") %>% 
  tab_header(
    title = md("**Table 4. Sound cue reporting.**")) %>% 
  tab_source_note("Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.") %>% 
  fmt_number(columns = c(no, maybe,  total), decimals = 0) %>% 
  tab_spanner( 
    label = md("**Reported Hearing Cue on Verbal Report?**"), 
    columns = c(no, maybe, total)
    ) %>% 
  tab_stubhead(label = md("**Reported Hearing Cue on Exit Questionnaire?**")
  ) %>% 
  cols_label(no = md("**No**"), maybe = md("**Maybe**"), total = md("***Total***"), label = " ")
Table 4. Sound cue reporting.
Reported Hearing Cue on Exit Questionnaire? Reported Hearing Cue on Verbal Report?
No Maybe Total
No 26 2 28
Maybe 2 0 2
Total 28 2 30
Participants’ responses to the postnap verbal inquiry and to the exit questionnaire. A response was not recorded for n = 1 participant; this participant reported that they did not hear the sound cue on the final exit questionnaire.

Reproducing Figure 4