Analysis walkthrough for the paper “Good-enough production: Selecting easier words instead of accurate ones.” (Koranda, Zettersten, & MacDonald, 2020).

See WordChoice_codebook for information about individual columns.

First, load all data across Experiments 1-4.

all_data <- read.csv(here::here("processed_data","Words_final_preprocessed.csv"))

Experiment 1

#load data
d <- filter(all_data,version=="exp1")

Demographics

Overview over the demographics of participants in Experiment 1.

#demographics and by-subject accuracy for each block
subjDemographics <- d %>%
  select(subjCode,Gender,Age,NativeLang,SecondLangYN) %>%
  unique() %>%
  summarize(
    N=n(),
    gender_f=sum(Gender=="Female"),
    mean_age=round(mean(Age,na.rm=T),2),
    sd_age=round(sd(Age,na.rm=T),2),
    min_age=round(min(Age,na.rm=T),2),
    max_age=round(max(Age,na.rm=T),2),
    native_english=sum(NativeLang=="Yes"),
    language_besides_english=sum(SecondLangYN=="Yes"),
  )

kable(subjDemographics)
N gender_f mean_age sd_age min_age max_age native_english language_besides_english
39 25 18.84 0.86 18 21 38 9

Overall Pair Learning Accuracy

Overview of participants’ performance during the Training Phase in which word participants learn each of the 8 compass directions.

#generate by-subject accuracy for each block (repeated training blocks are averaged together)
subjAcc <- d %>%
  group_by(subjCode,trialType) %>%
  summarize(
    accuracy=mean(isRight,na.rm=T),
    numTrials=sum(!is.na(subjCode)),
    rt = mean(rt,na.rm=T)) %>%
  ungroup()

#Overall Accuracy Pair Learning
overallPairAcc <- subjAcc %>%
  filter(trialType=="pairLearn") %>%
  summarize(
    acc=mean(accuracy,na.rm=T),
    sd = sd(accuracy),
    num_trials_avg = mean(numTrials),
    num_trials_sd = sd(numTrials),
    num_blocks_avg = mean(numTrials/20),
    num_blocks_sd= sd(numTrials/20))
kable(overallPairAcc)
acc sd num_trials_avg num_trials_sd num_blocks_avg num_blocks_sd
0.9520604 0.0308001 91.79487 38.58496 4.589744 1.929248

Final word retention

Timed Retention Test

Participants’ performance during the Timed Retention test at the conclusion of the experiment.

Accuracy

#summarize subject accuracy by frequency
subjAccFreq <- d %>%
  group_by(subjCode,block,freq) %>%
  summarize(
    accuracy=mean(isRight,na.rm=T),
    rt = mean(rt,na.rm=T)) %>%
  ungroup()

testXAcc <-  summarySEwithin(data=subset(subjAccFreq,block=="test_x"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
testXAcc$lowerCI <-  testXAcc$accuracy - testXAcc$ci
testXAcc$upperCI <- testXAcc$accuracy + testXAcc$ci
kable(testXAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 39 0.9166667 0.9166667 0.1357941 0.0217445 0.0440193 0.8726473 0.9606860
lf 39 0.8461538 0.8461538 0.1357941 0.0217445 0.0440193 0.8021345 0.8901732
#t-test
t.test(subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = 1.9858, df = 38, p-value = 0.05431
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.001370471  0.142396112
## sample estimates:
## mean of the differences 
##              0.07051282

Reaction Times

# reaction times
testXRT <-  summarySEwithin(subset(subjAccFreq,block=="test_x"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
testXRT$lowerCI <-  testXRT$rt - testXRT$ci
testXRT$upperCI <-  testXRT$rt + testXRT$ci
kable(testXRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 39 2346.792 2346.792 437.0367 69.98187 141.6709 2205.121 2488.463
lf 39 2628.082 2628.082 437.0367 69.98187 141.6709 2486.412 2769.753
#t-test
t.test(subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = -2.4614, df = 38, p-value = 0.01849
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -512.63778  -49.94257
## sample estimates:
## mean of the differences 
##               -281.2902

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(testXAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
  #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  xlab("Accuracy")+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(testXRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="test_x"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

# save plot
ggsave(here::here("plots","exp1_testXCheck.jpg"), width=9, height=6)

Untimed Retention Test

Participants’ performance on the Untimed Retention test at the conclusion of the experiment.

Accuracy

# accuracy
nameCheckAcc <-  summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
nameCheckAcc$lowerCI <-  nameCheckAcc$accuracy - nameCheckAcc$ci
nameCheckAcc$upperCI <-  nameCheckAcc$accuracy + nameCheckAcc$ci
kable(nameCheckAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 39 0.974359 0.974359 0.0702439 0.011248 0.0227704 0.9515885 0.9971294
lf 39 0.974359 0.974359 0.0702439 0.011248 0.0227704 0.9515885 0.9971294
#t-test
t.test(subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = 0, df = 38, p-value = 1
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.03718399  0.03718399
## sample estimates:
## mean of the differences 
##                       0

Reaction Times

# reaction times
nameCheckRT <-  summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
nameCheckRT$lowerCI <-  nameCheckRT$rt - nameCheckRT$ci
nameCheckRT$upperCI <-  nameCheckRT$rt + nameCheckRT$ci
kable(nameCheckRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 39 2755.277 2755.277 685.6555 109.7928 222.2638 2533.013 2977.541
lf 39 3080.391 3080.391 685.6555 109.7928 222.2638 2858.127 3302.655
#t-test
t.test(subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = -1.8133, df = 38, p-value = 0.07768
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -688.06881   37.84174
## sample estimates:
## mean of the differences 
##               -325.1135

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(nameCheckAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(nameCheckRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="name_check"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp1_finalNameCheck.jpg"), width=9, height=6)

Frequency Effect on Word Choice

Main Model

In our main analysis, we considered participants’ likelihood of choosing the word for the nearest compass direction, dependent on whether that compass direction was a high- or a low-frequency word, while controlling for the distance from the nearest learned compass direction. We focused specifically on low-frequency/high-frequency trials, in which a compass direction was tested in between a low-frequency and a high-frequency trained direction.

As a conservative test, we retained only trials in which participants chose one of the two principal direction words within 45° of the stimulus direction (94.41% of all low-frequency/high-frequency trials).

#just trials with a left or right angle choice
#model
m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2453.4   2514.6  -1216.7   2433.4     3348 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -8.9254  0.0982  0.2040  0.4370  2.2482 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.240227 0.49013             
##              hfTrial             1.211711 1.10078  -0.26      
##              angleDiffFromMatchC 0.001383 0.03719  -0.98  0.06
##  targetLabel (Intercept)         0.020018 0.14149             
## Number of obs: 3358, groups:  subjCode, 39; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.34236    0.12216  19.174  < 2e-16 ***
## hfTrial              0.70564    0.20946   3.369 0.000755 ***
## angleDiffFromMatchC -0.22760    0.01347 -16.892  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial     -0.145       
## anglDffFrMC -0.778  0.039
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          2.1029300  2.5817911
## hfTrial              0.2951182  1.1161689
## angleDiffFromMatchC -0.2540037 -0.2011891
#calculate shift in x-axis units (degrees of angle)
shift_x <- -(summary(m)$coefficients[1,1]+0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1]
#low 95% CI
shift_x_lower <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1]
#high 95% CI
shift_x_upper <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1]

## Main model has a singular fit warning - since this fit does not appear to impact fit, we retained the more complex random effects structure.
## However, we also fit a simplified model with the random slope for (the less theoretically important predictor) angleDiffFromMatchC removed, to ensure that the results are similar across different random effects structures and to alleviate concerns about a the boundary fit.
## This model yields very similar results (uncomment model below to view)
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

This effect corresponded to an estimated 3.1° shift (95% CI = [1.3°, 4.9°]) in participants’ decision boundary for high-frequency words as compared to low-frequency words.

Robustness Checks

Controlling for final retention accuracy of labels on each trial

To ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we first re-fit the model while controlling for participants’ accuracy during the Untimed Retention Test for the two (nearby) compass directions involved in each trial.

#controlling for accuracy for nearby labels
m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: 
## matchChoice ~ hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels +  
##     (1 + hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2461.2   2553.0  -1215.6   2431.2     3343 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -9.3204  0.0982  0.2044  0.4364  2.2383 
## 
## Random effects:
##  Groups      Name                      Variance Std.Dev. Corr             
##  subjCode    (Intercept)               0.210633 0.45895                   
##              hfTrial                   1.219664 1.10438  -0.83            
##              angleDiffFromMatchC       0.001256 0.03544   0.49  0.08      
##              finalAccuracyNearbyLabels 0.637278 0.79830  -0.81  0.35 -0.91
##  targetLabel (Intercept)               0.017727 0.13314                   
## Number of obs: 3358, groups:  subjCode, 39; targetLabel, 18
## 
## Fixed effects:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                1.97635    0.94416   2.093 0.036329 *  
## hfTrial                    0.71757    0.21023   3.413 0.000642 ***
## angleDiffFromMatchC       -0.22721    0.01337 -16.997  < 2e-16 ***
## finalAccuracyNearbyLabels  0.36827    0.95035   0.388 0.698380    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial     -0.054              
## anglDffFrMC -0.054  0.047       
## fnlAccrcyNL -0.991  0.038 -0.046
## convergence code: 1
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[12:15,]
##                                2.5 %     97.5 %
## (Intercept)                0.1258202  3.8268763
## hfTrial                    0.3055331  1.1296137
## angleDiffFromMatchC       -0.2534079 -0.2010068
## finalAccuracyNearbyLabels -1.4943857  2.2309223

Including only participants with perfect recall for all compass directions at the end of the experiment

To further ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we next re-fit the same model using a stricter inclusion criterion, including only participants who recalled all items correctly during the Untimed Retetion test.

final_accuracy <- d %>%
  filter(trialType=="finalName") %>%
  group_by(subjCode,trialType) %>%
  summarize(N=n(),accuracy=mean(isRight)) %>%
  ungroup()

#select only participants with perfect recall on the final test block
perfect_final_accuracy_subjects <- as.character(filter(final_accuracy,accuracy==1)$subjCode)

m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: 
## subset(d, listChoice == 1 & subjCode %in% perfect_final_accuracy_subjects)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2108.7   2168.6  -1044.3   2088.7     2946 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -8.7064  0.0947  0.1974  0.4321  2.1530 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.187489 0.43300             
##              hfTrial             0.785634 0.88636  -0.17      
##              angleDiffFromMatchC 0.001241 0.03523  -0.96 -0.11
##  targetLabel (Intercept)         0.074566 0.27307             
## Number of obs: 2956, groups:  subjCode, 34; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.46765    0.13898  17.755  < 2e-16 ***
## hfTrial              0.54033    0.19591   2.758  0.00582 ** 
## angleDiffFromMatchC -0.23838    0.01465 -16.268  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial     -0.085       
## anglDffFrMC -0.722 -0.001
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          2.1952530  2.7400423
## hfTrial              0.1563494  0.9243204
## angleDiffFromMatchC -0.2671023 -0.2096603
## maximal model yields a singular fit
## model with simpler random-effects structure (random slope for angleDiffFromMatchC removed) yields similar results without singular fit
# m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Controlling for compass direction character length

The words given to each of the compass directions varied in character length (and therefore perhaps in how easy they are to produce/ type). Beyond randomly assigning compass directions and counterbalancing their roles across participants, we also fit all models with by-item random effects to ensure that the effect of frequency generalizes across items. In the following model, we also explicitly control for character length to ensure that the effects hold even after accounting for character length of the nearest/ target compass direction.

m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+angleDiffFromMatchC+nearestLabel_length|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + nearestLabel_length +  
##     (1 + hfTrial + angleDiffFromMatchC + nearestLabel_length |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2444.1   2535.9  -1207.1   2414.1     3343 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -8.0225  0.0931  0.2010  0.4242  2.3324 
## 
## Random effects:
##  Groups      Name                Variance  Std.Dev.  Corr             
##  subjCode    (Intercept)         2.899e+00 1.703e+00                  
##              hfTrial             1.359e+00 1.166e+00 -0.04            
##              angleDiffFromMatchC 1.458e-03 3.819e-02  0.22  0.00      
##              nearestLabel_length 1.869e-01 4.323e-01 -0.96 -0.03 -0.46
##  targetLabel (Intercept)         8.176e-09 9.042e-05                  
## Number of obs: 3358, groups:  subjCode, 39; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.57496    0.39227   6.564 5.23e-11 ***
## hfTrial              0.68557    0.21902   3.130  0.00175 ** 
## angleDiffFromMatchC -0.23066    0.01371 -16.829  < 2e-16 ***
## nearestLabel_length -0.04607    0.09452  -0.487  0.62595    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial     -0.040              
## anglDffFrMC -0.096  0.021       
## nrstLbl_lng -0.955 -0.005 -0.144
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##        2.5 % 97.5 %
## .sig08    NA     NA
## .sig09    NA     NA
## .sig10    NA     NA
## maximal model yields a singular fit
## model with simpler random-effects structure (random slopes for angleDiffFromMatchC and nearestLabel_length removed) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Plot

Plot the effect of training frequency on word/ compass direction choice.

#refit model without centering angle for simpler plotting (coefficients essentially equivalent)
m <- glmer(matchChoice~hfTrial+angleDiffFromMatch+(1+hfTrial+angleDiffFromMatch|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

pX <- expand.grid(angleDiffFromMatch=seq(0,22.5,by=0.1),hfTrial=c(-0.5,0.5))

predictions <- predictSE(m,pX,re.form=NA, type="response")
pX$fit <- predictions$fit
pX$se.fit <- predictions$se.fit

### Three different plotting designs - same effect ###

# Plot 1

q <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,matchChoice,color=as.character(hfTrial)))+
  geom_jitter(width=0.5,height=0.03,alpha=0.2)+
  #geom_violinh(aes(y=as.factor(matchChoice),fill=as.character(hfTrial)),scale="count",width=0.3,alpha=0.3,color=NA)+
  #geom_violinhalf(aes(y=as.factor(matchChoice),fill=as.character(hfTrial)),scale="count",width=0.3,alpha=0.3,color=NA,orientation="y")+
  geom_smooth(data=pX,aes(y=fit,ymax=fit+se.fit,ymin=fit-se.fit,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))#+
  #ylim(-0.05,1.05)
ggsave(here::here("plots","exp1_frequencyEffect_old.jpg"), width=9, height=6)

#Plot 2

p_freq1 <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, alpha=0.3,shape=19,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 0.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
p_freq1

ggsave(here::here("plots","exp1_frequencyEffect.jpg"), width=9, height=6)

# Plot 3

#alternate
p <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, shape=19,alpha=0.2,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 1.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.75,alpha=0.4, color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.75,alpha=0.4,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
ggsave(here::here("plots","exp1_frequencyEffect_alternate.jpg"), width=9, height=6)

Experiment 2

#load data
d <- filter(all_data, version=="exp2")

Demographics

Overview over the demographics of participants in Experiment 1.

#demographics 
subjDemographics <- d %>%
  select(subjCode,Gender,Age,NativeLang,SecondLangYN) %>%
  unique() %>%
  summarize(
    N=n(),
    gender_f=sum(Gender=="Female"),
    mean_age=round(mean(Age,na.rm=T),2),
    sd_age=round(sd(Age,na.rm=T),2),
    min_age=round(min(Age,na.rm=T),2),
    max_age=round(max(Age,na.rm=T),2),
    native_english=sum(NativeLang=="Yes"),
    language_besides_english=sum(SecondLangYN=="Yes"),
  )

kable(subjDemographics)
N gender_f mean_age sd_age min_age max_age native_english language_besides_english
44 26 18.45 0.87 18 23 43 5

Overall Pair Learning Accuracy

Overview of participants’ performance during the Training Phase in which word participants learn each of the 8 compass directions.

#generate by-subject accuracy for each block (repeated training blocks are averaged together)
subjAcc <- d %>%
  group_by(subjCode,trialType) %>%
  summarize(accuracy=mean(isRight,na.rm=T),
              numTrials=sum(!is.na(subjCode)),
              rt = mean(rt,na.rm=T)) %>%
  ungroup()

#Overall Accuracy Pair Learning
overallPairAcc <- subjAcc %>%
  filter(trialType=="pairLearn") %>%
  summarize(
    acc=mean(accuracy,na.rm=T),
    sd = sd(accuracy),
    num_trials_avg = mean(numTrials),
    num_trials_sd = sd(numTrials),
    num_blocks_avg = mean(numTrials/20),
    num_blocks_sd= sd(numTrials/20))
kable(overallPairAcc)
acc sd num_trials_avg num_trials_sd num_blocks_avg num_blocks_sd
0.958008 0.0324513 87.27273 52.48981 4.363636 2.62449

Final word retention

Timed Retention Test

Participants’ performance during the Timed Retention test at the conclusion of the experiment.

Accuracy

#summarize subject accuracy by frequency
subjAccFreq <- d %>%
  group_by(subjCode,block,freq) %>%
  summarize(accuracy=mean(isRight,na.rm=T),
                  rt = mean(rt,na.rm=T)) %>%
  ungroup()

testXAcc <- summarySEwithin(data=subset(subjAccFreq,block=="test_x"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
testXAcc$lowerCI <- testXAcc$accuracy - testXAcc$ci
testXAcc$upperCI <- testXAcc$accuracy + testXAcc$ci
kable(testXAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 44 0.9375000 0.9375000 0.1404322 0.0211709 0.0426953 0.8948047 0.9801953
lf 44 0.8465909 0.8465909 0.1404322 0.0211709 0.0426953 0.8038956 0.8892862
#t-test
t.test(subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = 2.6296, df = 43, p-value = 0.01181
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.02118799 0.16063019
## sample estimates:
## mean of the differences 
##              0.09090909

Reaction Times

testXRT <- summarySEwithin(subset(subjAccFreq,block=="test_x"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
testXRT$lowerCI <- testXRT$rt - testXRT$ci
testXRT$upperCI <- testXRT$rt + testXRT$ci
kable(testXRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 44 2366.493 2366.493 367.5478 55.40992 111.7447 2254.748 2478.238
lf 44 2540.931 2540.931 367.5478 55.40992 111.7447 2429.187 2652.676
#t-test
t.test(subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = -1.9278, df = 43, p-value = 0.0605
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -356.916710    8.040105
## sample estimates:
## mean of the differences 
##               -174.4383

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(testXAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(testXRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="test_x"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp2_testXCheck.jpg"),width=9, height=6)

Untimed Retention Test

Participants’ performance on the Untimed Retention test at the conclusion of the experiment.

Accuracy

nameCheckAcc <- summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
nameCheckAcc$lowerCI <- nameCheckAcc$accuracy - nameCheckAcc$ci
nameCheckAcc$upperCI <- nameCheckAcc$accuracy + nameCheckAcc$ci
kable(nameCheckAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 44 0.9886364 0.9886364 0.0734074 0.0110666 0.0223179 0.9663185 1.0109542
lf 44 0.9488636 0.9488636 0.0734074 0.0110666 0.0223179 0.9265458 0.9711815
#t-test
t.test(subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = 2.2008, df = 43, p-value = 0.03317
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.003327778 0.076217677
## sample estimates:
## mean of the differences 
##              0.03977273

Reaction Times

nameCheckRT <- summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
nameCheckRT$lowerCI <- nameCheckRT$rt - nameCheckRT$ci
nameCheckRT$upperCI <- nameCheckRT$rt + nameCheckRT$ci
kable(nameCheckRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 44 2683.890 2683.890 693.0014 104.4739 210.6917 2473.198 2894.581
lf 44 2982.349 2982.349 693.0014 104.4739 210.6917 2771.657 3193.041
#t-test
t.test(subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = -1.7494, df = 43, p-value = 0.08735
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -642.5172   45.5989
## sample estimates:
## mean of the differences 
##               -298.4592

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(nameCheckAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(nameCheckRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="name_check"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp2_finalNameCheck.jpg"), width=9, height=6)

Frequency Effect on Word Choice

Main Model

As in Experiment 1, we considered participants’ likelihood of choosing the word for the nearest compass direction, dependent on whether that compass direction was a high- or a low-frequency word, while controlling for the distance from the nearest learned compass direction. We focused specifically on low-frequency/high-frequency trials, in which a compass direction was tested in between a low-frequency and a high-frequency trained direction.

As a conservative test, we retained only trials in which participants chose one of the two principal direction words within 45° of the stimulus direction (93.78% of all low-frequency/high-frequency trials).

#just trials with a left or right angle choice
m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1961.2   2019.4   -970.6   1941.2     2477 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.5877  0.0733  0.2173  0.4400  3.2164 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.19173  0.43787             
##              hfTrial             3.47024  1.86286   0.16      
##              angleDiffFromMatchC 0.00165  0.04062  -1.00 -0.16
##  targetLabel (Intercept)         0.08061  0.28392             
## Number of obs: 2487, groups:  subjCode, 44; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          1.98412    0.13135  15.105  < 2e-16 ***
## hfTrial              1.35682    0.31086   4.365 1.27e-05 ***
## angleDiffFromMatchC -0.18780    0.01394 -13.476  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.129       
## anglDffFrMC -0.637 -0.075
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          1.7266685  2.2415632
## hfTrial              0.7475493  1.9660902
## angleDiffFromMatchC -0.2151160 -0.1604871
#calculate shift in x-axis units (degrees of angle)
shift_x <- -(summary(m)$coefficients[1,1]+0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1]
#low 95% CI
shift_x_lower <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1]
#high 95% CI
shift_x_upper <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1]

## maximal model yields a singular fit
## model with simpler random-effects structure (random slope for angleDiffFromMatchC removed) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

This effect corresponded to an estimated 7.22° shift (95% CI = [3.98°, 10.47°]) in participants’ decision boundary for high-frequency words as compared to low-frequency words.

Robustness Checks

Controlling for final retention accuracy of labels on each trial

To ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we first re-fit the model while controlling for participants’ accuracy during the Untimed Retention Test for the two (nearby) compass directions involved in each trial.

#controlling for accuracy for nearby labels
m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: 
## matchChoice ~ hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels +  
##     (1 + hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1962.7   2050.0   -966.4   1932.7     2472 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.8718  0.0705  0.2146  0.4369  3.0736 
## 
## Random effects:
##  Groups      Name                      Variance Std.Dev. Corr             
##  subjCode    (Intercept)               1.031544 1.01565                   
##              hfTrial                   3.454947 1.85875  -0.07            
##              angleDiffFromMatchC       0.001705 0.04129  -0.05 -0.22      
##              finalAccuracyNearbyLabels 1.349101 1.16151  -0.92  0.15 -0.36
##  targetLabel (Intercept)               0.078372 0.27995                   
## Number of obs: 2487, groups:  subjCode, 44; targetLabel, 18
## 
## Fixed effects:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                0.57991    0.74863   0.775   0.4386    
## hfTrial                    1.35958    0.31051   4.379 1.19e-05 ***
## angleDiffFromMatchC       -0.19049    0.01415 -13.467  < 2e-16 ***
## finalAccuracyNearbyLabels  1.46634    0.75835   1.934   0.0532 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial      0.001              
## anglDffFrMC -0.035 -0.098       
## fnlAccrcyNL -0.984  0.029 -0.082
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[12:15,]
##                                 2.5 %     97.5 %
## (Intercept)               -0.88737414  2.0472006
## hfTrial                    0.75098907  1.9681708
## angleDiffFromMatchC       -0.21821691 -0.1627695
## finalAccuracyNearbyLabels -0.01999638  2.9526832
## maximal model yields a singular fit
## model with simpler random-effects structure (removing non-theoretically important random slope for angleDiffFromMatchC) yields similar results for frequency effect without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Including only participants with perfect recall for all compass directions at the end of the experiment

To further ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we next re-fit the same model using a stricter inclusion criterion, including only participants who recalled all items correctly during the Untimed Retetion test.

final_accuracy <- d %>%
  filter(trialType=="finalName") %>%
  group_by(subjCode,trialType) %>%
  summarize(N=n(),accuracy=mean(isRight)) %>%
  ungroup()

#select only participants with perfect recall on the final test block
perfect_final_accuracy_subjects <- as.character(filter(final_accuracy,accuracy==1)$subjCode)

m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: 
## subset(d, listChoice == 1 & subjCode %in% perfect_final_accuracy_subjects)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1611.8   1667.8   -795.9   1591.8     1990 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.9569  0.0908  0.2327  0.4591  2.0653 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.18320  0.42802             
##              hfTrial             1.85778  1.36301   0.26      
##              angleDiffFromMatchC 0.00146  0.03822  -0.97 -0.01
##  targetLabel (Intercept)         0.05249  0.22910             
## Number of obs: 2000, groups:  subjCode, 35; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          1.99128    0.13653  14.585  < 2e-16 ***
## hfTrial              1.19493    0.27050   4.417 9.99e-06 ***
## angleDiffFromMatchC -0.18848    0.01542 -12.227  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.182       
## anglDffFrMC -0.686 -0.005
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          1.7236917  2.2588695
## hfTrial              0.6647553  1.7251108
## angleDiffFromMatchC -0.2186979 -0.1582714
## maximal model yields a singular fit
## model with simpler random-effects structure (random slope for angleDiffFromMatchC removed) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1& subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Controlling for compass direction character length

The words given to each of the compass directions varied in character length (and therefore perhaps in how easy they are to produce/ type). Beyond randomly assigning compass directions and counterbalancing their roles across participants, we also fit all models with by-item random effects to ensure that the effect of frequency generalizes across items. In the following model, we also explicitly control for character length to ensure that the effects hold even after accounting for character length of the nearest/ target compass direction.

m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+angleDiffFromMatchC+nearestLabel_length|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + nearestLabel_length +  
##     (1 + hfTrial + angleDiffFromMatchC + nearestLabel_length |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1941.9   2029.2   -955.9   1911.9     2472 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -6.2233  0.0650  0.1983  0.4176  2.7406 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr             
##  subjCode    (Intercept)         7.669988 2.76947                   
##              hfTrial             4.252725 2.06221  -0.06            
##              angleDiffFromMatchC 0.002073 0.04553  -0.40 -0.03      
##              nearestLabel_length 0.338741 0.58201  -0.99  0.09  0.27
##  targetLabel (Intercept)         0.065591 0.25611                   
## Number of obs: 2487, groups:  subjCode, 44; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          1.35321    0.61768   2.191   0.0285 *  
## hfTrial              1.38450    0.34421   4.022 5.77e-05 ***
## angleDiffFromMatchC -0.19457    0.01496 -13.005  < 2e-16 ***
## nearestLabel_length  0.16549    0.13645   1.213   0.2252    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial     -0.027              
## anglDffFrMC -0.213 -0.033       
## nrstLbl_lng -0.975  0.060  0.069
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##        2.5 % 97.5 %
## .sig08    NA     NA
## .sig09    NA     NA
## .sig10    NA     NA
## maximal model yields a singular fit
## model with simpler random-effects structure (random slope for angleDiffFromMatchC removed) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+nearestLabel_length|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Plot

Plot the effect of training frequency on word/ compass direction choice.

#refit model without centering angle for simpler plotting (coefficients roughly equivalent)
m <- glmer(matchChoice~hfTrial+angleDiffFromMatch+(1+hfTrial+angleDiffFromMatch|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

pX <- expand.grid(angleDiffFromMatch=seq(0,22.5,by=0.1),hfTrial=c(-0.5,0.5))

predictions <- predictSE(m,pX,re.form=NA, type="response")
pX$fit <- predictions$fit
pX$se.fit <- predictions$se.fit

#### Three different plot options - same basic design ####

# Plot 1

q <- ggplot(subset(d, trialType=="test"),aes(angleDiffFromMatch,matchChoice,color=as.character(hfTrial)))+
  geom_jitter(width=0.5,height=0.03,alpha=0.2)+
  #geom_violinh(aes(y=matchChoice,group=hfTrial),scale="count",width=0.5)+
  geom_smooth(data=pX,aes(y=fit,ymax=fit+se.fit,ymin=fit-se.fit,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing nearest word")+
  scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  scale_fill_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  xlab("Distance from nearest word")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))+
  ylim(-0.05,1.05)
ggsave(here::here("plots","exp2_frequencyEffect_old.jpg"), width=9, height=6)

# Plot 2

p_freq2 <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, alpha=0.3,shape=19,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 0.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
p_freq2

ggsave(here::here("plots","exp2_frequencyEffect.jpg"), width=9, height=6)

# Plot 3

#alternate
p <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, shape=19,alpha=0.2,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 1.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.75,alpha=0.4, color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.75,alpha=0.4,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
ggsave(here::here("plots","exp2_frequencyEffect_alternate.jpg"), width=9, height=6)

Experiment 3

#load data
d <- filter(all_data,version=="exp3")

Demographics

Overview over the demographics of participants in Experiment 1.

#demographics
subjDemographics <- d %>%
  select(subjCode,Gender,Age,NativeLang,SecondLangYN) %>%
  unique() %>%
  summarize(
    N=n(),
    gender_f=sum(Gender=="Female"),
    mean_age=round(mean(Age,na.rm=T),2),
    sd_age=round(sd(Age,na.rm=T),2),
    min_age=round(min(Age,na.rm=T),2),
    max_age=round(max(Age,na.rm=T),2),
    native_english=sum(NativeLang=="Yes"),
    language_besides_english=sum(SecondLangYN=="Yes"),
  )

kable(subjDemographics)
N gender_f mean_age sd_age min_age max_age native_english language_besides_english
55 38 18.87 0.88 18 22 54 6

Overall Pair Learning Accuracy

Overview of participants’ performance during the Training Phase in which word participants learn each of the 8 compass directions.

#generate by-subject accuracy for each block (repeated training blocks are averaged together)
subjAcc <- d %>%
  group_by(subjCode,trialType) %>%
  summarize(
    accuracy=mean(isRight,na.rm=T),
    numTrials=sum(!is.na(subjCode)),
    rt = mean(rt,na.rm=T)) %>%
  ungroup()

#Overall Accuracy Pair Learning
overallPairAcc <- subjAcc %>%
  filter(trialType=="pairLearn") %>%
  summarize(
    acc=mean(accuracy,na.rm=T),
    sd = sd(accuracy),
    numTrialsAvg = mean(numTrials),
    numTrialsSD = sd(numTrials),
    numBlocksAvg = mean(numTrials/20),
    numBlocksSD = sd(numTrials/20))
kable(overallPairAcc)
acc sd numTrialsAvg numTrialsSD numBlocksAvg numBlocksSD
0.9441321 0.0415011 92.72727 39.88198 4.636364 1.994099

Final word retention

Timed Retention Test

Participants’ performance during the Timed Retention test at the conclusion of the experiment.

Accuracy

#summarize subject accuracy by frequency
subjAccFreq <- d %>%
  group_by(subjCode,block,freq) %>%
  summarize(accuracy=mean(isRight,na.rm=T),
                  rt = mean(rt,na.rm=T)) %>%
  ungroup()

testXAcc <- summarySEwithin(data=subset(subjAccFreq,block=="test_x"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
testXAcc$lowerCI <- testXAcc$accuracy - testXAcc$ci
testXAcc$upperCI <- testXAcc$accuracy + testXAcc$ci
kable(testXAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 55 0.9181818 0.9181818 0.1390466 0.018749 0.0375896 0.8805922 0.9557714
lf 55 0.8954545 0.8954545 0.1390466 0.018749 0.0375896 0.8578650 0.9330441
#t-test
t.test(subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = 0.74231, df = 54, p-value = 0.4611
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.03865624  0.08411078
## sample estimates:
## mean of the differences 
##              0.02272727

Reaction Times

testXRT <- summarySEwithin(subset(subjAccFreq,block=="test_x"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
testXRT$lowerCI <- testXRT$rt - testXRT$ci
testXRT$upperCI <- testXRT$rt + testXRT$ci
kable(testXRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 55 2311.104 2311.104 336.0712 45.31583 90.85277 2220.251 2401.956
lf 55 2447.317 2447.317 336.0712 45.31583 90.85277 2356.464 2538.170
#t-test
t.test(subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = -1.8407, df = 54, p-value = 0.07116
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -284.57566   12.14825
## sample estimates:
## mean of the differences 
##               -136.2137

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(testXAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(testXRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="test_x"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp3_testXCheck.jpg"), width=9, height=6)

Untimed Retention Test

Participants’ performance on the Untimed Retention test at the conclusion of the experiment.

Accuracy

nameCheckAcc <- summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
nameCheckAcc$lowerCI <- nameCheckAcc$accuracy - nameCheckAcc$ci
nameCheckAcc$upperCI <- nameCheckAcc$accuracy + nameCheckAcc$ci
kable(nameCheckAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 55 0.9772727 0.9772727 0.0867664 0.0116996 0.0234562 0.9538165 1.0007290
lf 55 0.9500000 0.9500000 0.0867664 0.0116996 0.0234562 0.9265438 0.9734562
#t-test
t.test(subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = 1.4275, df = 54, p-value = 0.1592
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -0.01103116  0.06557662
## sample estimates:
## mean of the differences 
##              0.02727273

Reaction Times

nameCheckRT <- summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
nameCheckRT$lowerCI <- nameCheckRT$rt - nameCheckRT$ci
nameCheckRT$upperCI <- nameCheckRT$rt + nameCheckRT$ci
kable(nameCheckRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 55 2580.696 2580.696 500.9667 67.55034 135.4303 2445.266 2716.126
lf 55 2603.112 2603.112 500.9667 67.55034 135.4303 2467.682 2738.543
#t-test
t.test(subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = -0.20321, df = 54, p-value = 0.8397
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -243.5731  198.7403
## sample estimates:
## mean of the differences 
##               -22.41637

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(nameCheckAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(nameCheckRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="name_check"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp3_finalNameCheck.jpg"), width=9, height=6)

Frequency Effect on Word Choice

Main Model

As in Experiments 1 & 2, we considered participants’ likelihood of choosing the word for the nearest compass direction, dependent on whether that compass direction was a high- or a low-frequency word, while controlling for the distance from the nearest learned compass direction. We focused specifically on low-frequency/high-frequency trials, in which a compass direction was tested in between a low-frequency and a high-frequency trained direction.

As a conservative test, we retained only trials in which participants chose one of the two principal direction words within 45° of the stimulus direction (95.17% of all low-frequency/high-frequency trials).

#just trials with a left or right angle choice
m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2244.4   2304.9  -1112.2   2224.4     3143 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -9.3833  0.0842  0.1958  0.3990  2.9865 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.194531 0.44106             
##              hfTrial             4.020349 2.00508   0.00      
##              angleDiffFromMatchC 0.001765 0.04201  -0.99  0.13
##  targetLabel (Intercept)         0.124657 0.35307             
## Number of obs: 3153, groups:  subjCode, 55; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.29960    0.14009  16.416   <2e-16 ***
## hfTrial              1.17394    0.30173   3.891    1e-04 ***
## angleDiffFromMatchC -0.19687    0.01387 -14.195   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.060       
## anglDffFrMC -0.619  0.040
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          2.0250385  2.5741703
## hfTrial              0.5825591  1.7653226
## angleDiffFromMatchC -0.2240504 -0.1696861
#calculate shift in x-axis units (degrees of angle)
shift_x <- -(summary(m)$coefficients[1,1]+0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1]
#low 95% CI
shift_x_lower <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1]
#high 95% CI
shift_x_upper <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1]

## maximal model yields a singular fit
## model with simpler random-effects structure (random slope for angleDiffFromMatchC removed) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

This effect corresponded to an estimated 5.96° shift (95% CI = [2.96°, 8.97°]) in participants’ decision boundary for high-frequency words as compared to low-frequency words.

Robustness Checks

Controlling for final retention accuracy of labels on each trial

To ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we first re-fit the model while controlling for participants’ accuracy during the Untimed Retention Test for the two (nearby) compass directions involved in each trial.

#controlling for accuracy for nearby labels
#maximal model does not converge (degenerate Hessian) and has implausible standard errors
# m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

# refitting a simplified model with theoretically less important random slope removed (angleDiffFromMatchC)
m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: 
## matchChoice ~ hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels +  
##     (1 + hfTrial + finalAccuracyNearbyLabels | subjCode) + (1 |  
##     targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2227.5   2294.2  -1102.8   2205.5     3142 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -15.0671   0.0839   0.1980   0.3960   3.0173 
## 
## Random effects:
##  Groups      Name                      Variance Std.Dev. Corr       
##  subjCode    (Intercept)               2.9019   1.7035              
##              hfTrial                   3.9854   1.9963   -0.05      
##              finalAccuracyNearbyLabels 2.9531   1.7185   -1.00  0.08
##  targetLabel (Intercept)               0.1125   0.3353              
## Number of obs: 3153, groups:  subjCode, 55; targetLabel, 18
## 
## Fixed effects:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                0.52882    0.68369   0.773  0.43923    
## hfTrial                    1.20954    0.29876   4.048 5.15e-05 ***
## angleDiffFromMatchC       -0.19019    0.01146 -16.600  < 2e-16 ***
## finalAccuracyNearbyLabels  1.78809    0.68876   2.596  0.00943 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial     -0.030              
## anglDffFrMC -0.040  0.015       
## fnlAccrcyNL -0.985  0.050 -0.044
confint(m,method="Wald")[8:11,]
##                                2.5 %     97.5 %
## (Intercept)               -0.8111790  1.8688253
## hfTrial                    0.6239735  1.7950967
## angleDiffFromMatchC       -0.2126440 -0.1677335
## finalAccuracyNearbyLabels  0.4381496  3.1380337

Including only participants with perfect recall for all compass directions at the end of the experiment

To further ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we next re-fit the same model using a stricter inclusion criterion, including only participants who recalled all items correctly during the Untimed Retetion test.

final_accuracy <- d %>%
  filter(trialType=="finalName") %>%
  group_by(subjCode,trialType) %>%
  summarize(N=n(),accuracy=mean(isRight)) %>%
  ungroup()

#select only participants with perfect recall on the final test block
perfect_final_accuracy_subjects <- as.character(filter(final_accuracy,accuracy==1)$subjCode)

m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: 
## subset(d, listChoice == 1 & subjCode %in% perfect_final_accuracy_subjects)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1723.0   1781.0   -851.5   1703.0     2420 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -11.7263   0.0863   0.2002   0.4030   2.8142 
## 
## Random effects:
##  Groups      Name                Variance  Std.Dev. Corr       
##  subjCode    (Intercept)         0.0920585 0.30341             
##              hfTrial             3.7867560 1.94596   0.12      
##              angleDiffFromMatchC 0.0008041 0.02836  -0.97  0.14
##  targetLabel (Intercept)         0.0809354 0.28449             
## Number of obs: 2430, groups:  subjCode, 42; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.33787    0.12473  18.743  < 2e-16 ***
## hfTrial              0.98028    0.32847   2.984  0.00284 ** 
## angleDiffFromMatchC -0.19877    0.01388 -14.317  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.060       
## anglDffFrMC -0.605  0.071
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          2.0934018  2.5823363
## hfTrial              0.3364831  1.6240771
## angleDiffFromMatchC -0.2259792 -0.1715561
## maximal model yields a singular fit
## model with simpler random-effects structure (random slopes removed to allow convergence) yields similar results without singular fit
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Controlling for compass direction character length

The words given to each of the compass directions varied in character length (and therefore perhaps in how easy they are to produce/ type). Beyond randomly assigning compass directions and counterbalancing their roles across participants, we also fit all models with by-item random effects to ensure that the effect of frequency generalizes across items. In the following model, we also explicitly control for character length to ensure that the effects hold even after accounting for character length of the nearest/ target compass direction.

# Full model has convergence issues (Unlike other models, standard errors appear to be dramatically underestimated, presumably due to singular fit issue)
#m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

#Simplified model removing by-participant random slope for angleDiffFromMatchC (i.e. slope not relevant to the effect of interest; results are consistent, with more plausible standard errors)
m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+nearestLabel_length|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + nearestLabel_length +  
##     (1 + hfTrial + nearestLabel_length | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   2233.7   2300.4  -1105.9   2211.7     3142 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -14.7983   0.0843   0.1970   0.3892   2.7868 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         5.3085   2.3040              
##              hfTrial             4.0622   2.0155    0.10      
##              nearestLabel_length 0.2928   0.5411   -1.00 -0.10
##  targetLabel (Intercept)         0.1397   0.3738              
## Number of obs: 3153, groups:  subjCode, 55; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.11938    0.61525   3.445 0.000572 ***
## hfTrial              1.19682    0.30234   3.959 7.54e-05 ***
## angleDiffFromMatchC -0.19112    0.01146 -16.679  < 2e-16 ***
## nearestLabel_length  0.03820    0.14284   0.267 0.789132    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial      0.057              
## anglDffFrMC -0.104  0.012       
## nrstLbl_lng -0.979 -0.048  0.012
confint(m,method="Wald")[8:11,]
##                          2.5 %     97.5 %
## (Intercept)          0.9135186  3.3252364
## hfTrial              0.6042431  1.7893949
## angleDiffFromMatchC -0.2135754 -0.1686598
## nearestLabel_length -0.2417550  0.3181551

Plot

Plot the effect of training frequency on word/ compass direction choice.

#refit model without centering angle for simpler plotting,simplified random effects structure due to non-convergence (coefficients roughly equivalent, slight differences on second decimal point)
m <- glmer(matchChoice~hfTrial+angleDiffFromMatch+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

pX <- expand.grid(angleDiffFromMatch=seq(0,22.5,by=0.1),hfTrial=c(-0.5,0.5))

predictions <- predictSE(m,pX,re.form=NA, type="response")
pX$fit <- predictions$fit
pX$se.fit <- predictions$se.fit

#### Three different plot design options ####

# Plot 1

q <- ggplot(subset(d, trialType=="test"),aes(angleDiffFromMatch,matchChoice,color=as.character(hfTrial)))+
  geom_jitter(width=0.5,height=0.03,alpha=0.2)+
  #geom_violinh(aes(y=matchChoice,group=hfTrial),scale="count",width=0.5)+
  geom_smooth(data=pX,aes(y=fit,ymax=fit+se.fit,ymin=fit-se.fit,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing nearest word")+
  scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  scale_fill_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  xlab("Distance from nearest word")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))+
  ylim(-0.05,1.05)
ggsave(here::here("plots","exp3_frequencyEffect_old.jpg"), width=9, height=6)

# Plot 2

p_freq3 <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, alpha=0.3,shape=19,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 0.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
p_freq3

ggsave(here::here("plots","exp3_frequencyEffect.jpg"), width=9, height=6)

# Plot 3

#alternate
p <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, shape=19,alpha=0.2,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 1.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.75,alpha=0.4, color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.75,alpha=0.4,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
ggsave(here::here("plots","exp3_frequencyEffect_alternate.jpg"), width=9, height=6)

Experiment 4

#load data
d <- filter(all_data,version=="exp4")

#exclude subjects
excludeList <- c()
d <- subset(d, !(subjCode %in% excludeList))

Demographics

Overview over the demographics of participants in Experiment 1.

#demographics
subjDemographics <- d %>%
  select(subjCode,Gender,Age,NativeLang,SecondLangYN) %>%
  unique() %>%
  summarize(
    N=n(),
    gender_f=sum(Gender=="Female"),
    mean_age=round(mean(Age,na.rm=T),2),
    sd_age=round(sd(Age,na.rm=T),2),
    min_age=round(min(Age,na.rm=T),2),
    max_age=round(max(Age,na.rm=T),2),
    native_english=sum(NativeLang=="Yes"),
    language_besides_english=sum(SecondLangYN=="Yes"),
  )

kable(subjDemographics)
N gender_f mean_age sd_age min_age max_age native_english language_besides_english
43 24 18.72 0.88 18 21 43 5

Manipulation check

In Experiment 4, participants were first familiarized with the compass directions in order to unconfound visual familiarity with specific compass directions with naming experience with those compass directions. During Compass Practice Block, the compass directions for which a high-frequency name would later be assigned appeared four times less than the compass directions for which a low-frequency name would be assigned in a training task that did not involve assigning names to the compass direction.

Below, we verify that the manipulation was appropriately applied to each participant (to unconfound visual familiarity and naming experience), and summarize participants’ performance during the compass direction memory task.

#manipulation check
#is angle frequency expsoure during learning balanced
ggplot(subset(d,trialType=="pairLearn"|trialType=="nonvLearn"),aes(angle,fill=trialType))+
  geom_histogram(position=position_dodge())+
  facet_wrap(~subjCode)

ggsave(here::here("plots","exp4_learningAnglesManCheck.jpg"), width=9, height=6)

#generate by-subject accuracy for each block (repeated training blocks are averaged together)
subjAcc <- d %>%
  group_by(subjCode,trialType) %>%
  summarize(
    accuracy=mean(isRight,na.rm=T),
    numTrials=sum(!is.na(subjCode)),
    rt = mean(rt,na.rm=T)) %>%
  ungroup()

#accuracy on angle memory task
overallNonVLearn <- subjAcc %>%
  filter(trialType=="nonvLearn") %>%
  summarize(acc=mean(accuracy,na.rm=T),
            sd = sd(accuracy),
            rt=mean(rt))

kable(overallNonVLearn)
acc sd rt
0.9765116 0.0382899 1669.875

Overall Pair Learning Accuracy

Overview of participants’ performance during the Training Phase in which word participants learn each of the 8 compass directions.

#Overall Accuracy Pair Learning
overallPairAcc <- subjAcc %>%
  filter(trialType=="pairLearn") %>%
  summarize(
    acc=mean(accuracy,na.rm=T),
    sd = sd(accuracy),
    num_trials_avg = mean(numTrials),
    num_trials_sd = sd(numTrials),
    num_blocks_avg = mean(numTrials/20),
    num_blocks_sd= sd(numTrials/20))
kable(overallPairAcc)
acc sd num_trials_avg num_trials_sd num_blocks_avg num_blocks_sd
0.93 0.0767184 100 0 5 0

Final word retention

Timed Retention Test

Participants’ performance during the Timed Retention test at the conclusion of the experiment.

Accuracy

#summarize subject accuracy by frequency
subjAccFreq <- d %>%
  group_by(subjCode,block,freq) %>%
  summarize(accuracy=mean(isRight,na.rm=T),
            rt = mean(rt,na.rm=T)) %>%
  ungroup()

testXAcc <-  summarySEwithin(data=subset(subjAccFreq,block=="test_x"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
testXAcc$lowerCI <-  testXAcc$accuracy - testXAcc$ci
testXAcc$upperCI <-  testXAcc$accuracy + testXAcc$ci
kable(testXAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 43 0.9244186 0.9244186 0.1205607 0.0183853 0.0371031 0.8873155 0.9615217
lf 43 0.8313953 0.8313953 0.1205607 0.0183853 0.0371031 0.7942922 0.8684985
#t-test
t.test(subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$accuracy[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$accuracy[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = 3.0984, df = 42, p-value = 0.003464
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.03243413 0.15361238
## sample estimates:
## mean of the differences 
##              0.09302326

Reaction Times

# reaction times
testXRT <-  summarySEwithin(subset(subjAccFreq,block=="test_x"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
testXRT$lowerCI <- testXRT$rt - testXRT$ci
testXRT$upperCI <- testXRT$rt + testXRT$ci
kable(testXRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 43 2439.123 2439.123 322.5185 49.18362 99.25655 2339.866 2538.379
lf 43 2600.677 2600.677 322.5185 49.18362 99.25655 2501.421 2699.934
#t-test
t.test(subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="hf"],
       subset(subjAccFreq,block=="test_x")$rt[subset(subjAccFreq,block=="test_x")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "test_x")$rt[subset(subjAccFreq,     block == "test_x")$freq == "hf"] and     block == "test_x")$freq == "lf"]
## t = -2.0115, df = 42, p-value = 0.05072
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -323.6397997    0.5307484
## sample estimates:
## mean of the differences 
##               -161.5545

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(testXAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(testXRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="test_x"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="test_x"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp4_testXCheck.jpg"), width=9, height=6)

Untimed Retention Test

Participants’ performance on the Untimed Retention test at the conclusion of the experiment.

Accuracy

nameCheckAcc <-  summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="accuracy",withinvars=c("freq"),idvar="subjCode")
nameCheckAcc$lowerCI <-  nameCheckAcc$accuracy - nameCheckAcc$ci
nameCheckAcc$upperCI <-  nameCheckAcc$accuracy + nameCheckAcc$ci
kable(nameCheckAcc)
freq N accuracy accuracy_norm sd se ci lowerCI upperCI
hf 43 0.9767442 0.9767442 0.1149399 0.0175282 0.0353733 0.9413709 1.0121175
lf 43 0.9186047 0.9186047 0.1149399 0.0175282 0.0353733 0.8832314 0.9539779
#t-test
t.test(subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$accuracy[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$accuracy[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = 2.0312, df = 42, p-value = 0.0486
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.0003752313 0.1159038385
## sample estimates:
## mean of the differences 
##              0.05813953

Reaction Times

# reaction times
nameCheckRT <-  summarySEwithin(subset(subjAccFreq,block=="name_check"), measurevar="rt",withinvars=c("freq"),idvar="subjCode")
nameCheckRT$lowerCI <-  nameCheckRT$rt - nameCheckRT$ci
nameCheckRT$upperCI <-  nameCheckRT$rt + nameCheckRT$ci
kable(nameCheckRT)
freq N rt rt_norm sd se ci lowerCI upperCI
hf 43 2541.706 2541.706 588.5539 89.75362 181.1301 2360.576 2722.836
lf 43 2901.322 2901.322 588.5539 89.75362 181.1301 2720.191 3082.452
#t-test
t.test(subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="hf"],
       subset(subjAccFreq,block=="name_check")$rt[subset(subjAccFreq,block=="name_check")$freq=="lf"],paired=T)
## 
##  Paired t-test
## 
## data:  subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,  and subset(subjAccFreq, block == "name_check")$rt[subset(subjAccFreq,     block == "name_check")$freq == "hf"] and     block == "name_check")$freq == "lf"]
## t = -2.4536, df = 42, p-value = 0.01837
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -655.40004  -63.83147
## sample estimates:
## mean of the differences 
##               -359.6158

Plotting Accuracy and Reaction Times

#plot
p1 <- ggplot(nameCheckAcc,aes(freq,accuracy,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  theme_classic(base_size=20)+
  theme(legend.position="none")+
  ylim(0,1.05)

p2 <- ggplot(nameCheckRT,aes(freq,rt,color=freq,fill=freq))+
  geom_bar(stat="identity",alpha=0.5,size=1.2)+ 
  geom_violin(data=subset(subjAccFreq,block=="name_check"),fill=NA,alpha=0)+
  geom_jitter(data=subset(subjAccFreq,block=="name_check"),width=0.2,height=0.03)+
  geom_errorbar(aes(ymin=lowerCI,ymax=upperCI),width=0.05,color="black",size=1.2)+
    #scale_color_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                     #values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency",
  #                   breaks=c("hf","lf"),
  #                   labels=c("high-frequency","low-frequency"))+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency",
                     breaks=c("hf","lf"),
                     labels=c("high-frequency","low-frequency"))+
  scale_x_discrete(name="Frequency",breaks=c("hf","lf"),labels=c("high-frequency","low-frequency"))+
  ylab("Reaction Time (ms)")+
  theme_classic(base_size=20)+
  theme(legend.position="none")
p <- plot_grid(p1,p2)
p

ggsave(here::here("plots","exp4_finalNameCheck.jpg"), width=9, height=6)

Frequency Effect on Word Choice

Main Model

As in Experiments 1-3, we considered participants’ likelihood of choosing the word for the nearest compass direction, dependent on whether that compass direction was a high- or a low-frequency word, while controlling for the distance from the nearest learned compass direction. We focused specifically on low-frequency/high-frequency trials, in which a compass direction was tested in between a low-frequency and a high-frequency trained direction.

As a conservative test, we retained only trials in which participants chose one of the two principal direction words within 45° of the stimulus direction (93% of all low-frequency/high-frequency trials).

m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1799.0   1856.9   -889.5   1779.0     2408 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -6.9605  0.0936  0.2078  0.4086  1.8512 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.138414 0.37204             
##              hfTrial             3.349180 1.83008  -0.10      
##              angleDiffFromMatchC 0.001516 0.03894  -0.65  0.37
##  targetLabel (Intercept)         0.160130 0.40016             
## Number of obs: 2418, groups:  subjCode, 43; targetLabel, 18
## 
## Fixed effects:
##                      Estimate Std. Error  z value Pr(>|z|)    
## (Intercept)          2.289320   0.127399   17.970   <2e-16 ***
## hfTrial              0.702644   0.309260    2.272   0.0231 *  
## angleDiffFromMatchC -0.205366   0.001006 -204.070   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.069       
## anglDffFrMC -0.092 -0.019
## convergence code: 0
## unable to evaluate scaled gradient
## Model failed to converge: degenerate  Hessian with 1 negative eigenvalues
#confidence interval
confint(m,method="Wald")[8:10,]
##                           2.5 %     97.5 %
## (Intercept)          2.03962248  2.5390167
## hfTrial              0.09650574  1.3087822
## angleDiffFromMatchC -0.20733844 -0.2033936
#calculate shift in x-axis units (degrees of angle)
shift_x <- -(summary(m)$coefficients[1,1]+0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*summary(m)$coefficients[2,1])/summary(m)$coefficients[3,1]
#low 95% CI
shift_x_lower <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,1])/summary(m)$coefficients[3,1]
#high 95% CI
shift_x_upper <- -(summary(m)$coefficients[1,1]+0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1] + (summary(m)$coefficients[1,1]-0.5*confint(m,method="Wald")[8:10,][2,2])/summary(m)$coefficients[3,1]

# full model yields a convergence warning ((degenerate Hessian) - simplified model removing random slope for angleDiffFromMatchC yields consistent results (and no convergence warning)
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

This effect corresponded to an estimated 3.42° shift (95% CI = [0.47°, 6.37°]) in participants’ decision boundary for high-frequency words as compared to low-frequency words.

Robustness Checks

Controlling for final retention accuracy of labels on each trial

To ensure that the frequency effect is not an artifact of participants’ being slightly more likely to forget the low-frequency labels, we first re-fit the model while controlling for participants’ accuracy during the Untimed Retention Test for the two (nearby) compass directions involved in each trial.

#controlling for accuracy for nearby labels
m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels+(1+hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: 
## matchChoice ~ hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels +  
##     (1 + hfTrial + angleDiffFromMatchC + finalAccuracyNearbyLabels |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1801.7   1888.5   -885.8   1771.7     2403 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -7.1348  0.0957  0.2100  0.4058  2.0548 
## 
## Random effects:
##  Groups      Name                      Variance Std.Dev. Corr             
##  subjCode    (Intercept)               0.00000  0.00000                   
##              hfTrial                   3.30423  1.81775    NaN            
##              angleDiffFromMatchC       0.00174  0.04171    NaN  0.31      
##              finalAccuracyNearbyLabels 0.13984  0.37395    NaN  0.05 -0.52
##  targetLabel (Intercept)               0.13987  0.37400                   
## Number of obs: 2418, groups:  subjCode, 43; targetLabel, 18
## 
## Fixed effects:
##                           Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                1.12025    0.42743   2.621  0.00877 ** 
## hfTrial                    0.77964    0.31095   2.507  0.01217 *  
## angleDiffFromMatchC       -0.20524    0.01512 -13.576  < 2e-16 ***
## finalAccuracyNearbyLabels  1.23331    0.44153   2.793  0.00522 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial     -0.020              
## anglDffFrMC -0.095  0.125       
## fnlAccrcyNL -0.941  0.036 -0.088
## convergence code: 0
## boundary (singular) fit: see ?isSingular
confint(m,method="Wald")[12:15,]
##                                2.5 %     97.5 %
## (Intercept)                0.2825023  1.9579906
## hfTrial                    0.1701761  1.3890973
## angleDiffFromMatchC       -0.2348646 -0.1756064
## finalAccuracyNearbyLabels  0.3679288  2.0986984
# full model yields a singular fit - simplified model removing random slopes for angleDiffFromMatchC and finalAccuracyNearbyLabels yields consistent results (and no singular fit warning)
# m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+finalAccuracyNearbyLabels + (1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
# summary(m)

Including only participants with perfect recall for all compass directions at the end of the experiment

We next re-fit the same model using a stricter inclusion criterion, including only participants who recalled all items correctly during the Untimed Retetion test. Here, unlike in the previous three experiments, we found that the effect of frequency did not hold after removing 10 participants who did not have perfect accuracy on the Untimed Retention test.

final_accuracy <- d %>%
  filter(trialType=="finalName") %>%
  group_by(subjCode,trialType) %>%
  summarize(N=n(),accuracy=mean(isRight)) %>%
  ungroup()

#select only participants with perfect recall on the final test block
perfect_final_accuracy_subjects <- as.character(filter(final_accuracy,accuracy==1)$subjCode)

#Fit model
m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_final_accuracy_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: 
## subset(d, listChoice == 1 & subjCode %in% perfect_final_accuracy_subjects)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1370.8   1426.0   -675.4   1350.8     1839 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -7.8518  0.0964  0.2087  0.4125  1.8651 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr       
##  subjCode    (Intercept)         0.126882 0.35621             
##              hfTrial             2.413463 1.55353  -0.12      
##              angleDiffFromMatchC 0.001321 0.03635  -0.75 -0.01
##  targetLabel (Intercept)         0.034931 0.18690             
## Number of obs: 1849, groups:  subjCode, 33; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.40085    0.14550  16.500   <2e-16 ***
## hfTrial              0.42380    0.31291   1.354    0.176    
## angleDiffFromMatchC -0.22675    0.01765 -12.849   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial     -0.043       
## anglDffFrMC -0.721  0.008
confint(m,method="Wald")[8:10,]
##                          2.5 %     97.5 %
## (Intercept)          2.1156626  2.6860314
## hfTrial             -0.1894847  1.0370902
## angleDiffFromMatchC -0.2613393 -0.1921644

Selecting only participants with perfect recall on the final Word Learning block

Unlike Exps 1-3, participants in Exp 4 saw a fixed number of learning trials. Therefore, not all participants reached perfect accuracy by the end of the training phase. We therefore re-ran the main model including only participants with perfect recall on the final Word Learning block (i.e., participants who entered the test phase/ “Treasure Hunt” having scored perfectly on all compass directions).

subj_acc_name_block <- d %>%
  filter(trialType=="name"&block=="init"&!(is.na(nameBlockNum))) %>%
  group_by(subjCode,nameBlockNum) %>%
  summarize(N=n(),accuracy=mean(isRight)) %>%
  ungroup()

#select only participants with perfect recall on the final Word Learning block
perfect_learning_subjects <- as.character(filter(subj_acc_name_block,nameBlockNum==5&accuracy==1)$subjCode)

m=glmer(matchChoice~hfTrial+angleDiffFromMatchC+(1+hfTrial+angleDiffFromMatchC|subjCode)+(1|targetLabel),data=subset(d, listChoice==1&subjCode %in% perfect_learning_subjects),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + (1 + hfTrial +  
##     angleDiffFromMatchC | subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1 & subjCode %in% perfect_learning_subjects)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1218.7   1272.6   -599.4   1198.7     1613 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -6.7350  0.0970  0.2075  0.4154  1.7457 
## 
## Random effects:
##  Groups      Name                Variance  Std.Dev. Corr       
##  subjCode    (Intercept)         0.1065132 0.3264              
##              hfTrial             3.0559540 1.7481   -0.04      
##              angleDiffFromMatchC 0.0009061 0.0301   -0.54  0.55
##  targetLabel (Intercept)         0.2031222 0.4507              
## Number of obs: 1623, groups:  subjCode, 29; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.28376    0.17533  13.025   <2e-16 ***
## hfTrial              0.73460    0.36701   2.002   0.0453 *  
## angleDiffFromMatchC -0.19956    0.01724 -11.574   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril
## hfTrial      0.003       
## anglDffFrMC -0.530  0.174
confint(m,method="Wald")[8:10,]
##                           2.5 %     97.5 %
## (Intercept)          1.94011610  2.6273990
## hfTrial              0.01528331  1.4539178
## angleDiffFromMatchC -0.23335627 -0.1657692

Controlling for compass direction character length

The words given to each of the compass directions varied in character length (and therefore perhaps in how easy they are to produce/ type). Beyond randomly assigning compass directions and counterbalancing their roles across participants, we also fit all models with by-item random effects to ensure that the effect of frequency generalizes across items. In the following model, we also explicitly control for character length to ensure that the effects hold even after accounting for character length of the nearest/ target compass direction.

m <- glmer(matchChoice~hfTrial+angleDiffFromMatchC+nearestLabel_length+(1+hfTrial+angleDiffFromMatchC+nearestLabel_length|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))
summary(m)
## Generalized linear mixed model fit by maximum likelihood (Laplace
##   Approximation) [glmerMod]
##  Family: binomial  ( logit )
## Formula: matchChoice ~ hfTrial + angleDiffFromMatchC + nearestLabel_length +  
##     (1 + hfTrial + angleDiffFromMatchC + nearestLabel_length |  
##         subjCode) + (1 | targetLabel)
##    Data: subset(d, listChoice == 1)
## Control: glmerControl(optimizer = "bobyqa")
## 
##      AIC      BIC   logLik deviance df.resid 
##   1777.5   1864.3   -873.7   1747.5     2403 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -6.2867  0.0808  0.1917  0.3867  1.9896 
## 
## Random effects:
##  Groups      Name                Variance Std.Dev. Corr             
##  subjCode    (Intercept)         9.275998 3.04565                   
##              hfTrial             4.279920 2.06880   0.24            
##              angleDiffFromMatchC 0.001115 0.03339   0.12  0.59      
##              nearestLabel_length 0.513307 0.71645  -0.99 -0.26 -0.20
##  targetLabel (Intercept)         0.211573 0.45997                   
## Number of obs: 2418, groups:  subjCode, 43; targetLabel, 18
## 
## Fixed effects:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          2.22324    0.79270   2.805  0.00504 ** 
## hfTrial              0.80548    0.35238   2.286  0.02227 *  
## angleDiffFromMatchC -0.21190    0.01528 -13.869  < 2e-16 ***
## nearestLabel_length  0.04229    0.18352   0.230  0.81775    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) hfTril anDFMC
## hfTrial      0.143              
## anglDffFrMC -0.080  0.180       
## nrstLbl_lng -0.978 -0.150 -0.031
confint(m,method="Wald")[12:15,]
##                          2.5 %     97.5 %
## (Intercept)          0.6695770  3.7769124
## hfTrial              0.1148197  1.4961369
## angleDiffFromMatchC -0.2418455 -0.1819543
## nearestLabel_length -0.3174086  0.4019904

Plot

Plot the effect of training frequency on word/ compass direction choice.

#refit model without centering angle for simpler plotting (coefficients roughly equivalent)
m <- glmer(matchChoice~hfTrial+angleDiffFromMatch+(1+hfTrial|subjCode)+(1|targetLabel),data=subset(d, listChoice==1),family=binomial,glmerControl(optimizer="bobyqa"))

pX <- expand.grid(angleDiffFromMatch=seq(0,22.5,by=0.1),hfTrial=c(-0.5,0.5))

predictions <- predictSE(m,pX,re.form=NA, type="response")
pX$fit <- predictions$fit
pX$se.fit <- predictions$se.fit

#### Three different plotting design options ####

# Plot 1

q <- ggplot(subset(d, trialType=="test"),aes(angleDiffFromMatch,matchChoice,color=as.character(hfTrial)))+
  geom_jitter(width=0.5,height=0.03,alpha=0.2)+
  #geom_violinh(aes(y=matchChoice,group=hfTrial),scale="count",width=0.5)+
  geom_smooth(data=pX,aes(y=fit,ymax=fit+se.fit,ymin=fit-se.fit,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing nearest word")+
  scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  scale_fill_brewer(palette="Set1",name="Frequency of Nearest Word",
                     breaks=c(-0.5,0.5),
                     labels=c("Low-Frequency","High-Frequency"),direction=-1)+
  xlab("Distance from nearest word")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))+
  ylim(-0.05,1.05)
ggsave(here::here("plots","exp4_frequencyEffect_old.jpg"), width=9, height=6)

# Plot 2

p_freq4 <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, alpha=0.3,shape=19,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 0.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.4,alpha=0.5,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
p_freq4

ggsave(here::here("plots","exp4_frequencyEffect.jpg"), width=9, height=6)

# Plot 3

#alternate
p <- ggplot(subset(d, trialType=="test"&!is.na(matchChoice)),aes(angleDiffFromMatch,as.factor(matchChoice),color=as.character(hfTrial)))+
geom_point(size = 0.5, shape=19,alpha=0.2,position = position_jitterdodge(jitter.width = 0.05,jitter.height = 0.5,
dodge.width = 1.2,
seed = 1
))+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = .3 ),scale="count",width=0.75,alpha=0.4, color=NA)+
  geom_violinh(data=subset(d, trialType=="test"&!is.na(matchChoice)&hfTrial==-0.5),aes(fill=as.character(hfTrial)),position = position_nudge(x = 0, y = -.3 ),scale="count",width=0.75,alpha=0.4,color=NA)+
  geom_smooth(data=pX,aes(y=fit*4+1,ymax=(fit+se.fit)*4+1,ymin=(fit-se.fit)*4+1,fill=as.character(hfTrial)),stat="identity")+
  theme_classic(base_size=18)+
  ylab("Probability of choosing\nnearest compass direction")+
  # scale_color_brewer(palette="Set1",name="Frequency of Nearest Word",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_color_manual(values = c("#E41A1C","#377EB8"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  # scale_fill_brewer(palette="Set1",name="Frequency of Nearest Compass Direction",
  #                    breaks=c(0.5,-0.5),
  #                    labels=c("High-Frequency","Low-Frequency"),direction=-1)+
  scale_fill_manual(values = c("#E41A1C","#BDE0ED"),
                    name="Frequency of Compass Direction",
                     breaks=c(0.5,-0.5),
                     labels=c("High-Frequency","Low-Frequency"))+
  scale_y_discrete(limits=c("0","0.25","0.5","0.75","1"))+
  xlab("Distance from nearest compass direction")+
  geom_vline(xintercept=22.5,linetype="dashed")+
  theme(legend.position=c(0.4,0.4))
ggsave(here::here("plots","exp4_frequencyEffect_alternate.jpg"), width=9, height=6)