Similarity Ratings Analyses
Libraries and Data Files
#load libraries
library(dplyr)
library(ggplot2)
library(emmeans)
library(lme4)
library(lmerTest)
#load data
data<-read.csv("AllData_SimilarityRatings.csv", header = T)
Data Pre-processing
#rename useful variables
data$sbj<-data$participant
data$resp<-data$slider_exp.response
data$block<-data$blocks.thisN +1
data <- mutate_if(data, is.character, as.factor)
data$sbj<-as.factor(data$sbj)
str(data)
## 'data.frame': 9648 obs. of 38 variables:
## $ trl : int 20 12 17 14 21 3 10 13 6 23 ...
## $ cnd : Factor w/ 2 levels "between","within": 2 2 2 2 1 2 2 2 2 1 ...
## $ dim : Factor w/ 2 levels "irrel","rel": 2 1 2 2 2 1 1 2 1 2 ...
## $ size1 : num 3.4 2.6 2.2 2.6 2.2 2.2 2.6 2.2 3 3 ...
## $ hue1 : num 0.1 0.3 0.1 -0.3 -0.1 0.1 -0.1 -0.3 -0.1 -0.1 ...
## $ size2 : num 3.4 3 2.2 2.6 2.2 2.6 3 2.2 3.4 3 ...
## $ hue2 : num 0.3 0.3 0.3 -0.1 0.1 0.1 -0.1 -0.1 -0.1 0.1 ...
## $ practice_trials.thisRepN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisTrialN: logi NA NA NA NA NA NA ...
## $ practice_trials.thisN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisIndex : logi NA NA NA NA NA NA ...
## $ blocks.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisTrialN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisIndex : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisTrialN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisIndex : int 19 11 16 13 20 2 9 12 5 22 ...
## $ break_loop.thisRepN : logi NA NA NA NA NA NA ...
## $ break_loop.thisTrialN : logi NA NA NA NA NA NA ...
## $ break_loop.thisN : logi NA NA NA NA NA NA ...
## $ break_loop.thisIndex : logi NA NA NA NA NA NA ...
## $ thisRow.t : num 68.9 73.1 75.9 79.7 82.8 ...
## $ notes : logi NA NA NA NA NA NA ...
## $ slider_exp.response : int 5 7 5 4 3 4 3 2 7 5 ...
## $ slider_exp.rt : num 3.89 2.6 3.45 2.87 4.87 ...
## $ participant : int 17202 17202 17202 17202 17202 17202 17202 17202 17202 17202 ...
## $ session : Factor w/ 2 levels "Post","Pre": 1 1 1 1 1 1 1 1 1 1 ...
## $ group : Factor w/ 4 levels "1100","1600",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ date : Factor w/ 134 levels "2025-02-25_11h40.18.454",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ expName : Factor w/ 1 level "SimilarityRatings": 1 1 1 1 1 1 1 1 1 1 ...
## $ psychopyVersion : Factor w/ 1 level "2023.2.3": 1 1 1 1 1 1 1 1 1 1 ...
## $ frameRate : num 60 60 60 60 60 ...
## $ expStart : Factor w/ 134 levels "2025-02-25 11h48.02.736634 +0200",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ sbj : Factor w/ 67 levels "341","1003","1206",..: 10 10 10 10 10 10 10 10 10 10 ...
## $ resp : int 5 7 5 4 3 4 3 2 7 5 ...
## $ block : num 1 1 1 1 1 1 1 1 1 1 ...
#re-order the levels of the session factor
data$session <- factor(data$session, levels = c("Pre", "Post"))
#exclude one participant (20335) for not following instructions
data<-droplevels(data[data$sbj!="20335",])
str(data)
## 'data.frame': 9504 obs. of 38 variables:
## $ trl : int 20 12 17 14 21 3 10 13 6 23 ...
## $ cnd : Factor w/ 2 levels "between","within": 2 2 2 2 1 2 2 2 2 1 ...
## $ dim : Factor w/ 2 levels "irrel","rel": 2 1 2 2 2 1 1 2 1 2 ...
## $ size1 : num 3.4 2.6 2.2 2.6 2.2 2.2 2.6 2.2 3 3 ...
## $ hue1 : num 0.1 0.3 0.1 -0.3 -0.1 0.1 -0.1 -0.3 -0.1 -0.1 ...
## $ size2 : num 3.4 3 2.2 2.6 2.2 2.6 3 2.2 3.4 3 ...
## $ hue2 : num 0.3 0.3 0.3 -0.1 0.1 0.1 -0.1 -0.1 -0.1 0.1 ...
## $ practice_trials.thisRepN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisTrialN: logi NA NA NA NA NA NA ...
## $ practice_trials.thisN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisIndex : logi NA NA NA NA NA NA ...
## $ blocks.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisTrialN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisIndex : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisTrialN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisIndex : int 19 11 16 13 20 2 9 12 5 22 ...
## $ break_loop.thisRepN : logi NA NA NA NA NA NA ...
## $ break_loop.thisTrialN : logi NA NA NA NA NA NA ...
## $ break_loop.thisN : logi NA NA NA NA NA NA ...
## $ break_loop.thisIndex : logi NA NA NA NA NA NA ...
## $ thisRow.t : num 68.9 73.1 75.9 79.7 82.8 ...
## $ notes : logi NA NA NA NA NA NA ...
## $ slider_exp.response : int 5 7 5 4 3 4 3 2 7 5 ...
## $ slider_exp.rt : num 3.89 2.6 3.45 2.87 4.87 ...
## $ participant : int 17202 17202 17202 17202 17202 17202 17202 17202 17202 17202 ...
## $ session : Factor w/ 2 levels "Pre","Post": 2 2 2 2 2 2 2 2 2 2 ...
## $ group : Factor w/ 4 levels "1100","1600",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ date : Factor w/ 132 levels "2025-02-25_11h40.18.454",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ expName : Factor w/ 1 level "SimilarityRatings": 1 1 1 1 1 1 1 1 1 1 ...
## $ psychopyVersion : Factor w/ 1 level "2023.2.3": 1 1 1 1 1 1 1 1 1 1 ...
## $ frameRate : num 60 60 60 60 60 ...
## $ expStart : Factor w/ 132 levels "2025-02-25 11h48.02.736634 +0200",..: 4 4 4 4 4 4 4 4 4 4 ...
## $ sbj : Factor w/ 66 levels "341","1003","1206",..: 10 10 10 10 10 10 10 10 10 10 ...
## $ resp : int 5 7 5 4 3 4 3 2 7 5 ...
## $ block : num 1 1 1 1 1 1 1 1 1 1 ...
#retain the full sample for sensitivity analysis
data_full <- data
#exclude five participants ("43423" "48888" "63018" "77337" "77623") for not meeting the learning criterion
data<-droplevels(data[!(data$sbj %in% c("43423","48888", "63018", "77337", "77623")), ])
str(data)
## 'data.frame': 8784 obs. of 38 variables:
## $ trl : int 20 12 17 14 21 3 10 13 6 23 ...
## $ cnd : Factor w/ 2 levels "between","within": 2 2 2 2 1 2 2 2 2 1 ...
## $ dim : Factor w/ 2 levels "irrel","rel": 2 1 2 2 2 1 1 2 1 2 ...
## $ size1 : num 3.4 2.6 2.2 2.6 2.2 2.2 2.6 2.2 3 3 ...
## $ hue1 : num 0.1 0.3 0.1 -0.3 -0.1 0.1 -0.1 -0.3 -0.1 -0.1 ...
## $ size2 : num 3.4 3 2.2 2.6 2.2 2.6 3 2.2 3.4 3 ...
## $ hue2 : num 0.3 0.3 0.3 -0.1 0.1 0.1 -0.1 -0.1 -0.1 0.1 ...
## $ practice_trials.thisRepN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisTrialN: logi NA NA NA NA NA NA ...
## $ practice_trials.thisN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisIndex : logi NA NA NA NA NA NA ...
## $ blocks.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisTrialN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisIndex : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisTrialN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisIndex : int 19 11 16 13 20 2 9 12 5 22 ...
## $ break_loop.thisRepN : logi NA NA NA NA NA NA ...
## $ break_loop.thisTrialN : logi NA NA NA NA NA NA ...
## $ break_loop.thisN : logi NA NA NA NA NA NA ...
## $ break_loop.thisIndex : logi NA NA NA NA NA NA ...
## $ thisRow.t : num 68.9 73.1 75.9 79.7 82.8 ...
## $ notes : logi NA NA NA NA NA NA ...
## $ slider_exp.response : int 5 7 5 4 3 4 3 2 7 5 ...
## $ slider_exp.rt : num 3.89 2.6 3.45 2.87 4.87 ...
## $ participant : int 17202 17202 17202 17202 17202 17202 17202 17202 17202 17202 ...
## $ session : Factor w/ 2 levels "Pre","Post": 2 2 2 2 2 2 2 2 2 2 ...
## $ group : Factor w/ 4 levels "1100","1600",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ date : Factor w/ 122 levels "2025-02-25_13h08.44.108",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ expName : Factor w/ 1 level "SimilarityRatings": 1 1 1 1 1 1 1 1 1 1 ...
## $ psychopyVersion : Factor w/ 1 level "2023.2.3": 1 1 1 1 1 1 1 1 1 1 ...
## $ frameRate : num 60 60 60 60 60 ...
## $ expStart : Factor w/ 122 levels "2025-02-25 13h09.40.421447 +0200",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ sbj : Factor w/ 61 levels "341","1003","1206",..: 10 10 10 10 10 10 10 10 10 10 ...
## $ resp : int 5 7 5 4 3 4 3 2 7 5 ...
## $ block : num 1 1 1 1 1 1 1 1 1 1 ...
Comparison of Responses from “Exclusion-Instructions”
Participants
#check if we can keep data from 5 first sbjs
data$excl_instr<-"no"
#For the first 5 participants, we need to register that the instructions were different.
#These 5 participants are: "17202","57393", "94372", "40242", "89443"
data[data$sbj=="17202" | data$sbj=="57393" | data$sbj=="94372" | data$sbj=="40242" | data$sbj=="89443",]$excl_instr<-"yes"
data$excl_instr<-as.factor(data$excl_instr)
str(data)
## 'data.frame': 8784 obs. of 39 variables:
## $ trl : int 20 12 17 14 21 3 10 13 6 23 ...
## $ cnd : Factor w/ 2 levels "between","within": 2 2 2 2 1 2 2 2 2 1 ...
## $ dim : Factor w/ 2 levels "irrel","rel": 2 1 2 2 2 1 1 2 1 2 ...
## $ size1 : num 3.4 2.6 2.2 2.6 2.2 2.2 2.6 2.2 3 3 ...
## $ hue1 : num 0.1 0.3 0.1 -0.3 -0.1 0.1 -0.1 -0.3 -0.1 -0.1 ...
## $ size2 : num 3.4 3 2.2 2.6 2.2 2.6 3 2.2 3.4 3 ...
## $ hue2 : num 0.3 0.3 0.3 -0.1 0.1 0.1 -0.1 -0.1 -0.1 0.1 ...
## $ practice_trials.thisRepN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisTrialN: logi NA NA NA NA NA NA ...
## $ practice_trials.thisN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisIndex : logi NA NA NA NA NA NA ...
## $ blocks.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisTrialN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisIndex : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisTrialN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisIndex : int 19 11 16 13 20 2 9 12 5 22 ...
## $ break_loop.thisRepN : logi NA NA NA NA NA NA ...
## $ break_loop.thisTrialN : logi NA NA NA NA NA NA ...
## $ break_loop.thisN : logi NA NA NA NA NA NA ...
## $ break_loop.thisIndex : logi NA NA NA NA NA NA ...
## $ thisRow.t : num 68.9 73.1 75.9 79.7 82.8 ...
## $ notes : logi NA NA NA NA NA NA ...
## $ slider_exp.response : int 5 7 5 4 3 4 3 2 7 5 ...
## $ slider_exp.rt : num 3.89 2.6 3.45 2.87 4.87 ...
## $ participant : int 17202 17202 17202 17202 17202 17202 17202 17202 17202 17202 ...
## $ session : Factor w/ 2 levels "Pre","Post": 2 2 2 2 2 2 2 2 2 2 ...
## $ group : Factor w/ 4 levels "1100","1600",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ date : Factor w/ 122 levels "2025-02-25_13h08.44.108",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ expName : Factor w/ 1 level "SimilarityRatings": 1 1 1 1 1 1 1 1 1 1 ...
## $ psychopyVersion : Factor w/ 1 level "2023.2.3": 1 1 1 1 1 1 1 1 1 1 ...
## $ frameRate : num 60 60 60 60 60 ...
## $ expStart : Factor w/ 122 levels "2025-02-25 13h09.40.421447 +0200",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ sbj : Factor w/ 61 levels "341","1003","1206",..: 10 10 10 10 10 10 10 10 10 10 ...
## $ resp : int 5 7 5 4 3 4 3 2 7 5 ...
## $ block : num 1 1 1 1 1 1 1 1 1 1 ...
## $ excl_instr : Factor w/ 2 levels "no","yes": 2 2 2 2 2 2 2 2 2 2 ...
#test if there's a difference in response distribution among participants (excl_instr= "yes" vs. "no")
table_sim<-table(data$resp, data$excl_instr)
chi_sim<-chisq.test(table_sim)
## Warning in chisq.test(table_sim): Chi-squared approximation may be incorrect
print(chi_sim)
##
## Pearson's Chi-squared test
##
## data: table_sim
## X-squared = 18.417, df = 8, p-value = 0.01831
#function to calculate the percentage of expected counts >=5)
check_expected_frequencies <- function(chisq_test_result) {
expected <- chisq_test_result$expected
total_cells <- length(expected)
cells_over_5 <- sum(expected >= 5)
percent_over_5 <- (cells_over_5 / total_cells) * 100
return(percent_over_5)
}
check_expected_frequencies(chi_sim)
## [1] 94.44444
# it should be >80%
#plot distribution
plot_sim <- data %>%
group_by(resp, excl_instr) %>%
summarise(n = n()) %>%
group_by(excl_instr) %>%
mutate(freq = n / sum(n))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by resp and excl_instr.
## ℹ Output is grouped by resp.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(resp, excl_instr))` for per-operation grouping
## (`?dplyr::dplyr_by`) instead.
ggplot(plot_sim, aes(x = as.factor(resp), y = freq, fill = excl_instr)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Response Distribution", x = "Response (1...9)", y = "Relative Frequency", fill = "Exclude\nInstructions") +
theme_minimal()

# exclude five early "exclusion instruction" participants
data <- droplevels( data[!(data$sbj %in% c("17202","57393", "94372", "40242", "89443")), ])
str(data)
## 'data.frame': 8064 obs. of 39 variables:
## $ trl : int 7 5 9 11 19 3 2 13 12 8 ...
## $ cnd : Factor w/ 2 levels "between","within": 2 2 2 2 2 2 2 2 2 2 ...
## $ dim : Factor w/ 2 levels "irrel","rel": 1 1 1 1 2 1 1 2 1 1 ...
## $ size1 : num 3 3 2.6 2.6 3 2.2 2.2 2.2 2.6 3 ...
## $ hue1 : num 0.1 -0.3 -0.3 0.1 0.1 0.1 -0.1 -0.3 0.3 0.3 ...
## $ size2 : num 3.4 3.4 3 3 3 2.6 2.6 2.2 3 3.4 ...
## $ hue2 : num 0.1 -0.3 -0.3 0.1 0.3 0.1 -0.1 -0.1 0.3 0.3 ...
## $ practice_trials.thisRepN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisTrialN: logi NA NA NA NA NA NA ...
## $ practice_trials.thisN : logi NA NA NA NA NA NA ...
## $ practice_trials.thisIndex : logi NA NA NA NA NA NA ...
## $ blocks.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisTrialN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ blocks.thisIndex : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisRepN : int 0 0 0 0 0 0 0 0 0 0 ...
## $ trials.thisTrialN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisN : int 0 1 2 3 4 5 6 7 8 9 ...
## $ trials.thisIndex : int 6 4 8 10 18 2 1 12 11 7 ...
## $ break_loop.thisRepN : logi NA NA NA NA NA NA ...
## $ break_loop.thisTrialN : logi NA NA NA NA NA NA ...
## $ break_loop.thisN : logi NA NA NA NA NA NA ...
## $ break_loop.thisIndex : logi NA NA NA NA NA NA ...
## $ thisRow.t : num 52.6 56.5 61 66.1 67.6 ...
## $ notes : logi NA NA NA NA NA NA ...
## $ slider_exp.response : int 9 8 6 7 8 4 3 4 2 3 ...
## $ slider_exp.rt : num 3.6 4.28 4.81 1.19 1.56 ...
## $ participant : int 81139 81139 81139 81139 81139 81139 81139 81139 81139 81139 ...
## $ session : Factor w/ 2 levels "Pre","Post": 2 2 2 2 2 2 2 2 2 2 ...
## $ group : Factor w/ 4 levels "1100","1600",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ date : Factor w/ 112 levels "2025-03-18_11h13.00.672",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ expName : Factor w/ 1 level "SimilarityRatings": 1 1 1 1 1 1 1 1 1 1 ...
## $ psychopyVersion : Factor w/ 1 level "2023.2.3": 1 1 1 1 1 1 1 1 1 1 ...
## $ frameRate : num 60 60 60 60 60 ...
## $ expStart : Factor w/ 112 levels "2025-03-18 11h13.54.820981 +0200",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ sbj : Factor w/ 56 levels "341","1003","1206",..: 42 42 42 42 42 42 42 42 42 42 ...
## $ resp : int 9 8 6 7 8 4 3 4 2 3 ...
## $ block : num 1 1 1 1 1 1 1 1 1 1 ...
## $ excl_instr : Factor w/ 1 level "no": 1 1 1 1 1 1 1 1 1 1 ...
#Check that there are 14 sbjs per group
data %>%
distinct(sbj, group) %>%
count(group)
## group n
## 1 1100 14
## 2 1600 14
## 3 600 14
## 4 RD 14
#Calculate standardized score for the resp variable.
data <- data %>%
group_by(sbj) %>%
mutate(
z_resp = (resp - mean(resp, na.rm = TRUE)) /
sd(resp, na.rm = TRUE)
) %>%
ungroup()
Similarity Ratings Plot
##########################################################
# Similarity Ratings, by Group, Session, and Pair Type
# Violin plots + within-subject trajectories (ggplot2)
##########################################################
#create new factor, condition (pair type) with three levels
data$condition<-as.factor(ifelse(data$cnd=="between", "between", ifelse(data$dim=="rel","within_rel","within_irrel" )))
ylb <- "Standardized Similarity Ratings"
xlb <- "Session"
group_levels <- c("600", "1100", "1600", "RD")
group_labels <- c("Group: 600 ms", "Group: 1100 ms", "Group: 1600 ms", "Group: Response Defined")
cond_levels <- c("between", "within_rel", "within_irrel")
cond_labels <- c("Between Category Pairs\nRelevant Dimension",
"Within Category Pairs\nRelevant Dimension",
"Within Category Pairs\nIrrelevant Dimension")
# Participant means per cell (sbj × group × condition × session)
plot_df <- data %>%
mutate(
group = factor(group, levels = group_levels, labels = group_labels),
condition = factor(condition, levels = cond_levels, labels = cond_labels)
) %>%
group_by(sbj, group, condition, session) %>%
summarise(z_resp = mean(z_resp, na.rm = TRUE), .groups = "drop") %>%
filter(!is.na(z_resp))
p_sim <- ggplot(plot_df, aes(x = session, y = z_resp)) +
geom_violin(aes(fill = session),
trim = FALSE, width = 0.8, color = NA, alpha = 0.55) +
geom_line(aes(group = sbj), color = "grey40", linewidth = 0.30, alpha = 0.70) +
geom_point(aes(group = sbj), color = "grey40", size = 0.80, alpha = 0.70) +
coord_cartesian(ylim = c(-1.5, 1.5)) +
facet_grid(group ~ condition) +
scale_fill_manual(values = c("grey25", "grey75")) +
labs(
title = "Similarity Ratings by Group, Session, and Pair Type",
x = xlb, y = ylb
) +
theme_classic(base_size = 11) +
theme(
legend.position = "none",
strip.background = element_blank(),
strip.text = element_text(face = "bold"), # facet titles bold
axis.title.x = element_text(face = "bold"), # axis titles bold
axis.title.y = element_text(face = "bold"),
axis.text.x = element_text(face = "bold"), # Pre/Post bold
plot.title = element_text(face = "bold", hjust = 0.5)
)
print(p_sim)

#graph for paper 600 x 750
LMMs - Inferential Analyses
data_lmm <- data %>%
ungroup() %>%
mutate(
# Fixed order of factor levels
group = factor(
group,
levels = c("600", "1100", "1600", "RD")
),
session = factor(
session,
levels = c("Pre", "Post")
),
condition = factor(
condition,
levels = c("between", "within_rel", "within_irrel")
),
# Identifier of each individual stimulus
stim1_id = paste0(
sprintf("%.1f", size1), "_",
sprintf("%.1f", hue1)
),
stim2_id = paste0(
sprintf("%.1f", size2), "_",
sprintf("%.1f", hue2)
),
# Order-independent stimulus-pair identifier
pair_id = factor(
ifelse(
stim1_id <= stim2_id,
paste(stim1_id, stim2_id, sep = "__"),
paste(stim2_id, stim1_id, sep = "__")
)
)
) %>%
select(
sbj, group, session, condition,
pair_id, block, resp, z_resp
) %>%
droplevels()
###################################
# Code within-participant effects
###################################
data_lmm <- data_lmm %>%
mutate(
# Post - Pre
session_c = ifelse(session == "Post", 0.5, -0.5),
# Two contrasts spanning the main effect of Pair Type
condition_c1 = case_when(
condition == "between" ~ 2/3,
condition == "within_rel" ~ -1/3,
condition == "within_irrel" ~ -1/3
),
condition_c2 = case_when(
condition == "between" ~ 0,
condition == "within_rel" ~ 0.5,
condition == "within_irrel" ~ -0.5
),
# Post - Pre change separately for each Pair Type
change_between = ifelse(
condition == "between",
session_c,
0
),
change_within_rel = ifelse(
condition == "within_rel",
session_c,
0
),
change_within_irrel = ifelse(
condition == "within_irrel",
session_c,
0
)
)
contrasts(data_lmm$group) <- contr.sum(4)
contrasts(data_lmm$session) <- contr.sum(2)
contrasts(data_lmm$condition) <- contr.sum(3)
##########################################################
# Model 1 (m_lmm_full): Full linear mixed-effects model
##########################################################
m_lmm_full <- lmer(
z_resp ~ group * session * condition +
(
0 +
condition_c1 +
condition_c2 +
change_between +
change_within_rel +
change_within_irrel
| sbj
) +
# General differences among stimulus pairs
(1 | pair_id)+
# Pair-specific Post-Pre change
(0 + session_c | pair_id) +
# Repeated evaluations of the same pair
# by the same participant
(1 | sbj:pair_id),
data = data_lmm,
REML = TRUE,
control = lmerControl(
optimizer = "bobyqa",
optCtrl = list(maxfun = 200000)
)
)
## boundary (singular) fit: see help('isSingular')
#Check convergence and singularity
m_lmm_full@optinfo$conv$lme4$messages
## [1] "boundary (singular) fit: see help('isSingular')"
isSingular(m_lmm_full, tol = 1e-4)
## [1] TRUE
VarCorr(m_lmm_full)
## Groups Name Std.Dev. Corr
## sbj.pair_id (Intercept) 0.080370
## sbj condition_c1 0.264272
## condition_c2 0.805398 0.995
## change_between 0.635871 0.234 0.196
## change_within_rel 0.622590 0.341 0.289 0.958
## change_within_irrel 0.591068 -0.386 -0.329 0.352 0.127
## pair_id session_c 0.020164
## pair_id.1 (Intercept) 0.112224
## Residual 0.747113
#######################################################################
#Model 2 (m_lmm_ind): Model with independent participant random slopes
#######################################################################
m_lmm_ind <- lmer(
z_resp ~ group * session * condition +
# General differences among Pair Types
(0 + condition_c1 | sbj) +
(0 + condition_c2 | sbj) +
# Post-Pre change separately for each Pair Type
(0 + change_between | sbj) +
(0 + change_within_rel | sbj) +
(0 + change_within_irrel | sbj) +
# Differences among the 24 stimulus pairs
(1 | pair_id) +
# Pair-specific Post-Pre change
(0 + session_c | pair_id) +
# Repeated evaluations of the same pair
# by the same participant
(1 | sbj:pair_id),
data = data_lmm,
REML = TRUE,
control = lmerControl(
optimizer = "bobyqa",
optCtrl = list(maxfun = 200000)
)
)
# Check convergence and singularity
m_lmm_ind@optinfo$conv$lme4$messages
## NULL
isSingular(m_lmm_ind, tol = 1e-4)
## [1] FALSE
VarCorr(m_lmm_ind)
## Groups Name Std.Dev.
## sbj.pair_id (Intercept) 0.083721
## sbj change_within_irrel 0.591058
## sbj.1 change_within_rel 0.622586
## sbj.2 change_between 0.635766
## sbj.3 condition_c2 0.814599
## sbj.4 condition_c1 0.261193
## pair_id session_c 0.020160
## pair_id.1 (Intercept) 0.112180
## Residual 0.747119
##########################################################
#Type III tests of fixed effects
##########################################################
anova_lmm <- anova( m_lmm_ind, type = 3, ddf = "Kenward-Roger")
anova_lmm
## Type III Analysis of Variance Table with Kenward-Roger's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## group 18.868 6.2892 3 1207.02 11.2672 2.716e-07 ***
## session 10.197 10.1967 1 137.37 18.2675 3.566e-05 ***
## condition 34.170 17.0849 2 52.12 30.3728 1.801e-09 ***
## group:session 1.894 0.6313 3 154.16 1.1310 0.3384119
## group:condition 16.072 2.6787 6 84.90 4.7345 0.0003324 ***
## session:condition 3.644 1.8220 2 95.65 3.2434 0.0433637 *
## group:session:condition 2.632 0.4386 6 122.03 0.7783 0.5884901
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
###############################################################
#Post-Pre change within each Pair Type averaged across Groups
###############################################################
emm_session_condition <- emmeans( m_lmm_ind, ~ session | condition, lmer.df = "kenward-roger", pbkrtest.limit = 10000)
## NOTE: Results may be misleading due to involvement in interactions
change_by_condition <- contrast(emm_session_condition,method = list("Post - Pre" = c(-1, 1)), by = "condition")
summary(change_by_condition,infer = c(TRUE, FALSE))
## condition = between:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.3542 0.0948 48.5 -0.545 -0.1637
##
## condition = within_rel:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.2566 0.0883 51.0 -0.434 -0.0793
##
## condition = within_irrel:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.0459 0.0826 51.6 -0.212 0.1199
##
## Results are averaged over the levels of: group
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
test(change_by_condition, by = NULL, adjust = "holm")
## contrast condition estimate SE df t.ratio p.value
## Post - Pre between -0.3542 0.0948 48.5 -3.738 0.0015
## Post - Pre within_rel -0.2566 0.0883 51.0 -2.905 0.0108
## Post - Pre within_irrel -0.0459 0.0826 51.6 -0.556 0.5809
##
## Results are averaged over the levels of: group
## Degrees-of-freedom method: kenward-roger
## P value adjustment: holm method for 3 tests
#############################################################################
# Theory-Guided Follow-Up Analysis
# Group Moderation of Diagnosticity-Dependent Perceptual Change
############################################################################
###############################################################
# Post-Pre change within each Pair Type and Group
###############################################################
emm_session_condition_group <- emmeans( m_lmm_ind, ~ session | condition * group, lmer.df = "kenward-roger", pbkrtest.limit = 10000)
change_by_condition_group <- contrast(emm_session_condition_group, method = list("Post - Pre" = c(-1, 1)), by = c("condition", "group"))
summary(change_by_condition_group, infer = c(TRUE, TRUE), adjust = "none")
## condition = between, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.3594 0.189 52.0 -0.7381 0.0193 -1.904 0.0624
##
## condition = within_rel, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2638 0.176 52.1 -0.6175 0.0898 -1.497 0.1404
##
## condition = within_irrel, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.3455 0.165 52.1 -0.6764 -0.0145 -2.095 0.0411
##
## condition = between, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.3334 0.189 52.0 -0.7121 0.0453 -1.767 0.0831
##
## condition = within_rel, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.1196 0.176 52.1 -0.4732 0.2341 -0.678 0.5005
##
## condition = within_irrel, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.0924 0.165 52.1 -0.4234 0.2385 -0.560 0.5777
##
## condition = between, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2548 0.189 52.0 -0.6335 0.1239 -1.350 0.1828
##
## condition = within_rel, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2332 0.176 52.1 -0.5869 0.1204 -1.323 0.1915
##
## condition = within_irrel, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre 0.2383 0.165 52.1 -0.0927 0.5692 1.445 0.1545
##
## condition = between, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.4692 0.189 52.0 -0.8479 -0.0905 -2.486 0.0162
##
## condition = within_rel, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.4099 0.176 52.1 -0.7635 -0.0562 -2.326 0.0240
##
## condition = within_irrel, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre 0.0160 0.165 52.1 -0.3150 0.3469 0.097 0.9233
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
###############################################################
# Theory-guided diagnosticity-dependent change within each group
###############################################################
warping_by_group <- contrast(change_by_condition_group, method = list("Diagnosticity-dependent change" = c(-0.5, -0.5, 1)),by = "group")
summary(warping_by_group, infer = c(TRUE, FALSE))
## group = 600:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change -0.0339 0.209 114 -0.4488 0.381
##
## group = 1100:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.1341 0.209 114 -0.2809 0.549
##
## group = 1600:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.4823 0.209 114 0.0674 0.897
##
## group = RD:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.4555 0.209 114 0.0405 0.870
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
###############################################################
# Theory-guided group contrast
###############################################################
theory_group_contrast <- contrast(warping_by_group, method = list( "Mean of 1100, 1600, and RD - 600" = c(-1, 1/3, 1/3, 1/3)), by = NULL)
summary(theory_group_contrast, infer = c(TRUE, TRUE), adjust = "none")
## contrast estimate SE df lower.CL upper.CL t.ratio
## Mean of 1100, 1600, and RD - 600 0.391 0.242 114 -0.0876 0.87 1.619
## p.value
## 0.1083
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
Exploratory Analyses, Accuracy ~ Perceptual Change
# Mean rating per participant, session, and pair type
sim_type <- aggregate(z_resp ~ sbj + group + session + condition, data = data,FUN = mean)
# Put Pre and Post in separate columns
sim_change <- reshape(sim_type, idvar = c("sbj", "group", "condition"), timevar = "session",direction = "wide")
# Calculate Post minus Pre change
sim_change$change <-
sim_change$z_resp.Post -
sim_change$z_resp.Pre
# Put the three pair types in separate columns
warping <- reshape(
sim_change[, c("sbj", "group", "condition", "change")],
idvar = c("sbj", "group"),
timevar = "condition",
direction = "wide"
)
# Calculate diagnosticity-dependent warping
warping$warping_index <-
warping$change.within_irrel -
(
warping$change.between +
warping$change.within_rel
) / 2
# Inspect the warping index
head(warping)
## sbj group change.between change.within_irrel change.within_rel
## 1 1003 1100 -0.6602845 0.1834124 -0.60526078
## 2 3402 1100 0.3057330 0.1528665 0.21019141
## 3 8227 1100 -1.2734562 0.2214706 -0.49830893
## 4 19052 1100 0.5853529 0.0000000 0.08780294
## 5 21505 1100 -0.7074160 -0.8449692 -0.56003769
## 6 24220 1100 -1.0469296 -1.1134013 -0.39883033
## warping_index
## 1 0.8161850
## 2 -0.1050957
## 3 1.1073532
## 4 -0.3365779
## 5 -0.2112423
## 6 -0.3905214
summary(warping$warping_index)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -1.4210 -0.3221 0.1755 0.2595 0.6630 2.9623
###############################
# Load categorization accuracy
###############################
d_cat <- read.csv("d_cat.csv", header = TRUE)
d_cat$sbj <- as.factor(d_cat$sbj)
warping$sbj <- as.factor(warping$sbj)
# Merge similarity and accuracy data
d_cor <- merge( d_cat,warping,by = c("sbj", "group")
)
# Keep complete observations
d_cor <- d_cor[complete.cases(d_cor$acc, d_cor$warping_index),]
###############################
# Pearson correlation
###############################
cor_accuracy_warping <- cor.test(d_cor$acc, d_cor$warping_index,method = "pearson")
cor_accuracy_warping
##
## Pearson's product-moment correlation
##
## data: d_cor$acc and d_cor$warping_index
## t = 0.30918, df = 54, p-value = 0.7584
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.2233323 0.3016038
## sample estimates:
## cor
## 0.04203636
###############################
# Simple linear regression
###############################
model_accuracy_warping <- lm(warping_index ~ acc, data = d_cor)
summary(model_accuracy_warping)
##
## Call:
## lm(formula = warping_index ~ acc, data = d_cor)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.70712 -0.58434 -0.08248 0.36673 2.66998
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.6079 2.8077 -0.217 0.829
## acc 1.0003 3.2353 0.309 0.758
##
## Residual standard error: 0.8054 on 54 degrees of freedom
## Multiple R-squared: 0.001767, Adjusted R-squared: -0.01672
## F-statistic: 0.09559 on 1 and 54 DF, p-value: 0.7584
# Confidence intervals for regression coefficients
confint(model_accuracy_warping)
## 2.5 % 97.5 %
## (Intercept) -6.237015 5.021156
## acc -5.486143 7.486711
Sensitivity Analyses - Category-Learning Sample
# Prepare full sample
data_full <- data_full %>% group_by(sbj) %>% mutate(z_resp = (resp - mean(resp, na.rm = TRUE)) / sd(resp, na.rm = TRUE)) %>% ungroup()
data_full$group <- factor(data_full$group, levels = c("600", "1100", "1600", "RD"))
data_full$session <- factor(data_full$session, levels = c("Pre", "Post"))
data_full$condition <- factor(ifelse(data_full$cnd == "between", "between", ifelse(data_full$dim == "rel", "within_rel", "within_irrel")), levels = c("between", "within_rel", "within_irrel"))
# Create stimulus-pair identifier
stim1_id <- paste0(sprintf("%.1f", data_full$size1), "_", sprintf("%.1f", data_full$hue1))
stim2_id <- paste0(sprintf("%.1f", data_full$size2), "_", sprintf("%.1f", data_full$hue2))
data_full$pair_id <- factor(ifelse(stim1_id <= stim2_id, paste(stim1_id, stim2_id, sep = "__"), paste(stim2_id, stim1_id, sep = "__")))
# Code within-participant effects
data_full$session_c <- ifelse(data_full$session == "Post", 0.5, -0.5)
data_full$condition_c1 <- ifelse(data_full$condition == "between", 2/3, -1/3)
data_full$condition_c2 <- ifelse(data_full$condition == "between", 0, ifelse(data_full$condition == "within_rel", 0.5, -0.5))
data_full$change_between <- ifelse(data_full$condition == "between", data_full$session_c, 0)
data_full$change_within_rel <- ifelse(data_full$condition == "within_rel", data_full$session_c, 0)
data_full$change_within_irrel <- ifelse(data_full$condition == "within_irrel", data_full$session_c, 0)
data_lmm_sens <- droplevels(data_full)
contrasts(data_lmm_sens$group) <- contr.sum(4)
contrasts(data_lmm_sens$session) <- contr.sum(2)
contrasts(data_lmm_sens$condition) <- contr.sum(3)
##########################################################
# Final LMM fitted to the full sample
##########################################################
m_lmm_sens <- lmer(
z_resp ~ group * session * condition +
(0 + condition_c1 | sbj) + (0 + condition_c2 | sbj) +
(0 + change_between | sbj) + (0 + change_within_rel | sbj) + (0 + change_within_irrel | sbj) +
(1 | pair_id) + (0 + session_c | pair_id) + (1 | sbj:pair_id),
data = data_lmm_sens, REML = TRUE,
control = lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 200000))
)
m_lmm_sens@optinfo$conv$lme4$messages
## NULL
isSingular(m_lmm_sens, tol = 1e-4)
## [1] FALSE
VarCorr(m_lmm_sens)
## Groups Name Std.Dev.
## sbj.pair_id (Intercept) 0.0890991
## sbj change_within_irrel 0.5849603
## sbj.1 change_within_rel 0.6406591
## sbj.2 change_between 0.6325847
## sbj.3 condition_c2 0.7912737
## sbj.4 condition_c1 0.2632722
## pair_id session_c 0.0095334
## pair_id.1 (Intercept) 0.1095738
## Residual 0.7483707
##########################################################
# Type III tests
##########################################################
anova_lmm_sens <- anova(m_lmm_sens, type = 3, ddf = "Kenward-Roger")
anova_lmm_sens
## Type III Analysis of Variance Table with Kenward-Roger's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## group 23.117 7.7056 3 1427.02 13.7585 7.556e-09 ***
## session 15.504 15.5035 1 160.35 27.6819 4.522e-07 ***
## condition 37.888 18.9440 2 53.13 33.5987 3.704e-10 ***
## group:session 2.297 0.7656 3 183.61 1.3670 0.254332
## group:condition 19.856 3.3093 6 101.68 5.8421 2.903e-05 ***
## session:condition 8.204 4.1021 2 112.04 7.2847 0.001061 **
## group:session:condition 2.154 0.3590 6 145.86 0.6359 0.701362
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##########################################################
# Post-Pre change within each Pair Type
##########################################################
emm_session_condition_sens <- emmeans(m_lmm_sens, ~ session | condition, lmer.df = "kenward-roger", pbkrtest.limit = 10000)
## NOTE: Results may be misleading due to involvement in interactions
change_by_condition_sens <- contrast(emm_session_condition_sens, method = list("Post - Pre" = c(-1, 1)), by = "condition")
summary(change_by_condition_sens, infer = c(TRUE, FALSE))
## condition = between:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.41165 0.0868 56.3 -0.586 -0.238
##
## condition = within_rel:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.33018 0.0835 60.3 -0.497 -0.163
##
## condition = within_irrel:
## contrast estimate SE df lower.CL upper.CL
## Post - Pre -0.00584 0.0754 60.9 -0.157 0.145
##
## Results are averaged over the levels of: group
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
test(change_by_condition_sens, by = NULL, adjust = "holm")
## contrast condition estimate SE df t.ratio p.value
## Post - Pre between -0.41165 0.0868 56.3 -4.742 <0.0001
## Post - Pre within_rel -0.33018 0.0835 60.3 -3.955 0.0004
## Post - Pre within_irrel -0.00584 0.0754 60.9 -0.077 0.9386
##
## Results are averaged over the levels of: group
## Degrees-of-freedom method: kenward-roger
## P value adjustment: holm method for 3 tests
##########################################################
# Theory-guided sensitivity contrast
##########################################################
emm_session_condition_group_sens <- emmeans(m_lmm_sens, ~ session | condition * group, lmer.df = "kenward-roger", pbkrtest.limit = 10000)
change_by_condition_group_sens <- contrast(emm_session_condition_group_sens, method = list("Post - Pre" = c(-1, 1)), by = c("condition", "group"))
summary(change_by_condition_group_sens, infer = c(TRUE, TRUE), adjust = "none")
## condition = between, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.4262 0.166 61.6 -0.7574 -0.0951 -2.573 0.0125
##
## condition = within_rel, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.3698 0.159 61.9 -0.6884 -0.0511 -2.320 0.0237
##
## condition = within_irrel, group = 600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2660 0.144 62.0 -0.5540 0.0219 -1.847 0.0695
##
## condition = between, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.4262 0.181 61.7 -0.7889 -0.0635 -2.349 0.0220
##
## condition = within_rel, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.1993 0.175 61.9 -0.5484 0.1497 -1.142 0.2580
##
## condition = within_irrel, group = 1100:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.0378 0.158 62.0 -0.3532 0.2776 -0.240 0.8113
##
## condition = between, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2905 0.170 61.6 -0.6312 0.0503 -1.704 0.0934
##
## condition = within_rel, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.2454 0.164 61.9 -0.5733 0.0825 -1.496 0.1397
##
## condition = within_irrel, group = 1600:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre 0.2067 0.148 62.0 -0.0896 0.5030 1.395 0.1681
##
## condition = between, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.5037 0.176 61.7 -0.8549 -0.1524 -2.867 0.0057
##
## condition = within_rel, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre -0.5062 0.169 61.9 -0.8442 -0.1683 -2.994 0.0039
##
## condition = within_irrel, group = RD:
## contrast estimate SE df lower.CL upper.CL t.ratio p.value
## Post - Pre 0.0738 0.153 62.0 -0.2316 0.3792 0.483 0.6307
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
warping_by_group_sens <- contrast(change_by_condition_group_sens, method = list("Diagnosticity-dependent change" = c(-0.5, -0.5, 1)), by = "group")
summary(warping_by_group_sens, infer = c(TRUE, FALSE))
## group = 600:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.132 0.184 137 -0.2324 0.496
##
## group = 1100:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.275 0.202 138 -0.1242 0.674
##
## group = 1600:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.475 0.190 137 0.0997 0.850
##
## group = RD:
## contrast estimate SE df lower.CL upper.CL
## Diagnosticity-dependent change 0.579 0.195 138 0.1923 0.965
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
theory_group_contrast_sens <- contrast(warping_by_group_sens, method = list("Mean of 1100, 1600, and RD - 600" = c(-1, 1/3, 1/3, 1/3)), by = NULL)
summary(theory_group_contrast_sens, infer = c(TRUE, TRUE), adjust = "none")
## contrast estimate SE df lower.CL upper.CL t.ratio
## Mean of 1100, 1600, and RD - 600 0.311 0.216 138 -0.116 0.738 1.438
## p.value
## 0.1526
##
## Degrees-of-freedom method: kenward-roger
## Confidence level used: 0.95
#######################################################
# Sensitivity Analysis
# Accuracy-Warping Relationship in the Full Sample
#######################################################
# Mean standardized rating per participant, session, and pair type
sim_type_full <- aggregate(z_resp ~ sbj + group + session + condition, data = data_full, FUN = mean)
# Calculate Post-Pre change
sim_change_full <- reshape(sim_type_full, idvar = c("sbj", "group", "condition"), timevar = "session", direction = "wide")
sim_change_full$change <- sim_change_full$z_resp.Post - sim_change_full$z_resp.Pre
# Put pair types in separate columns
warping_full <- reshape(sim_change_full[, c("sbj", "group", "condition", "change")], idvar = c("sbj", "group"), timevar = "condition", direction = "wide")
# Calculate diagnosticity-dependent warping
warping_full$warping_index <- warping_full$change.within_irrel - (warping_full$change.between + warping_full$change.within_rel) / 2
# Prepare one accuracy score per participant
accuracy_full <- aggregate(acc ~ sbj + group, data = d_cat, FUN = mean, na.rm = TRUE)
# Use common identifier formats
accuracy_full$sbj <- as.character(accuracy_full$sbj)
accuracy_full$group <- as.character(accuracy_full$group)
warping_full$sbj <- as.character(warping_full$sbj)
warping_full$group <- as.character(warping_full$group)
# Merge similarity and accuracy data
d_cor_full <- merge(accuracy_full, warping_full, by = c("sbj", "group"))
d_cor_full <- d_cor_full[complete.cases(d_cor_full$acc, d_cor_full$warping_index), ]
# Check the analysis sample
cat("Number of participants:", nrow(d_cor_full), "\n")
## Number of participants: 66
print(table(d_cor_full$group))
##
## 1100 1600 600 RD
## 15 17 18 16
# Pearson correlation
cor_accuracy_warping_full <- cor.test(d_cor_full$acc, d_cor_full$warping_index, method = "pearson")
print(cor_accuracy_warping_full)
##
## Pearson's product-moment correlation
##
## data: d_cor_full$acc and d_cor_full$warping_index
## t = 0.57373, df = 64, p-value = 0.5682
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.1735038 0.3082292
## sample estimates:
## cor
## 0.07153294
# Simple linear regression
model_accuracy_warping_full <- lm(warping_index ~ acc, data = d_cor_full)
summary(model_accuracy_warping_full)
##
## Call:
## lm(formula = warping_index ~ acc, data = d_cor_full)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.8197 -0.5734 -0.1241 0.4539 2.5570
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.5573 1.6041 -0.347 0.729
## acc 1.0696 1.8643 0.574 0.568
##
## Residual standard error: 0.8531 on 64 degrees of freedom
## Multiple R-squared: 0.005117, Adjusted R-squared: -0.01043
## F-statistic: 0.3292 on 1 and 64 DF, p-value: 0.5682
confint(model_accuracy_warping_full)
## 2.5 % 97.5 %
## (Intercept) -3.761984 2.647307
## acc -2.654728 4.793927
Session Information
sessionInfo()
## R version 4.6.1 (2026-06-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=English_United States.utf8
## [2] LC_CTYPE=English_United States.utf8
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=English_United States.utf8
##
## time zone: Europe/Athens
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] lmerTest_3.2-1 lme4_2.0-6 Matrix_1.7-5 emmeans_2.0.4 ggplot2_4.0.3
## [6] dplyr_1.2.1
##
## loaded via a namespace (and not attached):
## [1] tidyr_1.3.2 sass_0.4.10 generics_0.1.4
## [4] lattice_0.22-9 digest_0.6.39 magrittr_2.0.5
## [7] evaluate_1.0.5 grid_4.6.1 estimability_2.0.0
## [10] RColorBrewer_1.1-3 mvtnorm_1.4-2 fastmap_1.2.0
## [13] jsonlite_2.0.0 backports_1.5.1 purrr_1.2.2
## [16] scales_1.4.0 numDeriv_2016.8-1.1 jquerylib_0.1.4
## [19] reformulas_0.4.4 Rdpack_2.6.6 cli_3.6.6
## [22] rlang_1.3.0 rbibutils_2.4.1 splines_4.6.1
## [25] withr_3.0.3 cachem_1.1.0 yaml_2.3.12
## [28] parallel_4.6.1 pbkrtest_0.5.5 tools_4.6.1
## [31] nloptr_2.2.1 minqa_1.2.8 boot_1.3-32
## [34] broom_1.0.13 vctrs_0.7.3 R6_2.6.1
## [37] lifecycle_1.0.5 MASS_7.3-65 pkgconfig_2.0.3
## [40] pillar_1.11.1 bslib_0.11.0 gtable_0.3.6
## [43] glue_1.8.1 Rcpp_1.1.2 xfun_0.60
## [46] tibble_3.3.1 tidyselect_1.2.1 rstudioapi_0.19.0
## [49] knitr_1.51 farver_2.1.2 htmltools_0.5.9
## [52] nlme_3.1-169 rmarkdown_2.31 labeling_0.4.3
## [55] compiler_4.6.1 S7_0.2.2