1+ # 03_confidence-ratings.r - error confidence rating analyses
2+ # author: [your name]
3+
4+ # this script assumes it's sourced from batch_behavioral-analyses.r
5+ # with data & directories already loaded
6+
7+ library(tidyverse )
8+ library(ez )
9+ library(effsize )
10+
11+ cat(" \n === CONFIDENCE RATING ANALYSES ===\n " )
12+ cat(" started:" , as.character(Sys.time()), " \n\n " )
13+
14+ # create output directory for confidence analyses
15+ confidence_dir <- file.path(session_dir , " confidence_ratings" )
16+ dir.create(confidence_dir , showWarnings = FALSE )
17+
18+ # === prepare confidence data ===
19+ prepare_confidence_data <- function (data , condition_type , verbose = TRUE ) {
20+ # prepare data for confidence analyses
21+ #
22+ # inputs:
23+ # data - trial-level behavioral data
24+ # condition_type - "visible_correctness", "visible_error_type", or "invisible_response_type"
25+ # verbose - print info
26+ #
27+ # outputs:
28+ # tibble ready for anova
29+
30+ if (condition_type == " visible_correctness" ) {
31+ # visible: correct vs error × social vs nonsocial
32+ conf_data <- data %> %
33+ filter(
34+ code %in% c(111 , 112 , 113 , 211 , 212 , 213 ),
35+ ! is.na(confidenceRating )
36+ ) %> %
37+ mutate(
38+ subject = factor (subject ),
39+ social = factor (ifelse(code %in% c(111 , 112 , 113 ), " social" , " nonsocial" )),
40+ correctness = factor (ifelse(code %in% c(111 , 211 ), " correct" , " error" ))
41+ ) %> %
42+ select(subject , social , correctness , confidenceRating )
43+
44+ } else if (condition_type == " visible_error_type" ) {
45+ # visible: flanker vs nonflanker error × social vs nonsocial (errors only)
46+ conf_data <- data %> %
47+ filter(
48+ code %in% c(112 , 113 , 212 , 213 ), # errors only
49+ ! is.na(confidenceRating )
50+ ) %> %
51+ mutate(
52+ subject = factor (subject ),
53+ social = factor (ifelse(code %in% c(112 , 113 ), " social" , " nonsocial" )),
54+ error_type = factor (ifelse(code %in% c(112 , 212 ), " flanker" , " nonflanker" ))
55+ ) %> %
56+ select(subject , social , error_type , confidenceRating )
57+
58+ } else if (condition_type == " invisible_response_type" ) {
59+ # invisible: flanker error vs nonflanker guess × social vs nonsocial
60+ conf_data <- data %> %
61+ filter(
62+ code %in% c(102 , 104 , 202 , 204 ),
63+ ! is.na(confidenceRating )
64+ ) %> %
65+ mutate(
66+ subject = factor (subject ),
67+ social = factor (ifelse(code %in% c(102 , 104 ), " social" , " nonsocial" )),
68+ response_type = factor (ifelse(code %in% c(102 , 202 ), " flanker_error" , " nonflanker_guess" ))
69+ ) %> %
70+ select(subject , social , response_type , confidenceRating )
71+ }
72+
73+ if (verbose ) {
74+ cat(" prepared" , nrow(conf_data ), " trials for" , condition_type , " \n " )
75+ }
76+
77+ return (conf_data )
78+ }
79+
80+ # === run confidence analyses ===
81+
82+ # 1. visible: correctness × social
83+ if (CONFIDENCE_ANALYSES $ visible_correctness ) {
84+ cat(" \n 1. visible condition: correctness × social\n " )
85+ cat(" 2×2 anova: correct/error × social/nonsocial\n " )
86+
87+ # prepare data
88+ conf_correctness <- prepare_confidence_data(transformed_data , " visible_correctness" )
89+
90+ # calculate descriptives
91+ descriptives_correctness <- conf_correctness %> %
92+ group_by(social , correctness ) %> %
93+ summarise(
94+ n = n(),
95+ mean = mean(confidenceRating , na.rm = TRUE ),
96+ sd = sd(confidenceRating , na.rm = TRUE ),
97+ se = sd / sqrt(n ),
98+ .groups = " drop"
99+ )
100+
101+ cat(" \n descriptive statistics:\n " )
102+ print(descriptives_correctness )
103+
104+ # run 2×2 repeated measures anova
105+ anova_correctness <- ezANOVA(
106+ data = conf_correctness ,
107+ dv = confidenceRating ,
108+ wid = subject ,
109+ within = .(social , correctness ),
110+ detailed = TRUE ,
111+ type = 3
112+ )
113+
114+ cat(" \n anova results:\n " )
115+ print(anova_correctness $ ANOVA )
116+
117+ # extract ANOVA table & calculate partial eta squared
118+ anova_table_correctness <- anova_correctness $ ANOVA %> %
119+ mutate(
120+ partial_eta_sq = SSn / (SSn + SSd )
121+ )
122+
123+ # save results
124+ results_correctness <- list (
125+ descriptives = descriptives_correctness ,
126+ anova = anova_correctness ,
127+ anova_table = anova_table_correctness ,
128+ data = conf_correctness
129+ )
130+ saveRDS(results_correctness , file.path(confidence_dir , " visible_correctness.rds" ))
131+
132+ # save tables to tables directory
133+ save_descriptives_table(descriptives_correctness , " confidence_visible_correctness_descriptives" , tables_dir )
134+ save_anova_results(anova_table_correctness , " confidence_visible_correctness" , tables_dir )
135+
136+ # create plot
137+ plot_path <- file.path(confidence_dir , " confidence_visible_correctness.png" )
138+ plot_confidence_interaction(conf_correctness %> %
139+ mutate(is_error = correctness == " error" ),
140+ plot_type = " correctness" ,
141+ save_path = plot_path )
142+ }
143+
144+ # 2. visible: error type × social (errors only)
145+ if (CONFIDENCE_ANALYSES $ visible_error_type ) {
146+ cat(" \n 2. visible condition: error type × social (errors only)\n " )
147+ cat(" 2×2 anova: flanker/nonflanker × social/nonsocial\n " )
148+
149+ # prepare data
150+ conf_error_type <- prepare_confidence_data(transformed_data , " visible_error_type" )
151+
152+ # check sample sizes per cell
153+ cell_counts <- conf_error_type %> %
154+ group_by(subject , social , error_type ) %> %
155+ summarise(n_trials = n(), .groups = " drop" ) %> %
156+ group_by(social , error_type ) %> %
157+ summarise(n_subjects = n(), .groups = " drop" )
158+
159+ cat(" \n subjects per cell:\n " )
160+ print(cell_counts )
161+
162+ # only run if sufficient data
163+ if (all(cell_counts $ n_subjects > = 10 )) {
164+ # calculate descriptives
165+ descriptives_error_type <- conf_error_type %> %
166+ group_by(social , error_type ) %> %
167+ summarise(
168+ n = n(),
169+ mean = mean(confidenceRating , na.rm = TRUE ),
170+ sd = sd(confidenceRating , na.rm = TRUE ),
171+ se = sd / sqrt(n ),
172+ .groups = " drop"
173+ )
174+
175+ cat(" \n descriptive statistics:\n " )
176+ print(descriptives_error_type )
177+
178+ # run 2×2 repeated measures anova
179+ anova_error_type <- ezANOVA(
180+ data = conf_error_type ,
181+ dv = confidenceRating ,
182+ wid = subject ,
183+ within = .(social , error_type ),
184+ detailed = TRUE ,
185+ type = 3
186+ )
187+
188+ cat(" \n anova results:\n " )
189+ print(anova_error_type $ ANOVA )
190+
191+ # extract ANOVA table & calculate partial eta squared
192+ anova_table_error_type <- anova_error_type $ ANOVA %> %
193+ mutate(
194+ partial_eta_sq = SSn / (SSn + SSd )
195+ )
196+
197+ # save results
198+ results_error_type <- list (
199+ descriptives = descriptives_error_type ,
200+ anova = anova_error_type ,
201+ anova_table = anova_table_error_type ,
202+ data = conf_error_type
203+ )
204+ saveRDS(results_error_type , file.path(confidence_dir , " visible_error_type.rds" ))
205+
206+ # save tables to tables directory
207+ save_descriptives_table(descriptives_error_type , " confidence_visible_error_type_descriptives" , tables_dir )
208+ save_anova_results(anova_table_error_type , " confidence_visible_error_type" , tables_dir )
209+
210+ # create plot
211+ plot_path <- file.path(confidence_dir , " confidence_visible_error_type.png" )
212+ plot_confidence_interaction(conf_error_type %> %
213+ mutate(is_flanker = error_type == " flanker" ),
214+ plot_type = " error_type" ,
215+ save_path = plot_path )
216+
217+ } else {
218+ cat(" \n insufficient data for error type analysis\n " )
219+ }
220+ }
221+
222+ # 3. invisible: response type × social
223+ if (CONFIDENCE_ANALYSES $ invisible_response_type ) {
224+ cat(" \n 3. invisible condition: response type × social\n " )
225+ cat(" 2×2 anova: flanker error/nonflanker guess × social/nonsocial\n " )
226+
227+ # prepare data
228+ conf_response_type <- prepare_confidence_data(transformed_data , " invisible_response_type" )
229+
230+ # calculate descriptives
231+ descriptives_response_type <- conf_response_type %> %
232+ group_by(social , response_type ) %> %
233+ summarise(
234+ n = n(),
235+ mean = mean(confidenceRating , na.rm = TRUE ),
236+ sd = sd(confidenceRating , na.rm = TRUE ),
237+ se = sd / sqrt(n ),
238+ .groups = " drop"
239+ )
240+
241+ cat(" \n descriptive statistics:\n " )
242+ print(descriptives_response_type )
243+
244+ # run 2×2 repeated measures anova
245+ anova_response_type <- ezANOVA(
246+ data = conf_response_type ,
247+ dv = confidenceRating ,
248+ wid = subject ,
249+ within = .(social , response_type ),
250+ detailed = TRUE ,
251+ type = 3
252+ )
253+
254+ cat(" \n anova results:\n " )
255+ print(anova_response_type $ ANOVA )
256+
257+ # extract ANOVA table & calculate partial eta squared
258+ anova_table_response_type <- anova_response_type $ ANOVA %> %
259+ mutate(
260+ partial_eta_sq = SSn / (SSn + SSd )
261+ )
262+
263+ # save results
264+ results_response_type <- list (
265+ descriptives = descriptives_response_type ,
266+ anova = anova_response_type ,
267+ anova_table = anova_table_response_type ,
268+ data = conf_response_type
269+ )
270+ saveRDS(results_response_type , file.path(confidence_dir , " invisible_response_type.rds" ))
271+
272+ # save tables to tables directory
273+ save_descriptives_table(descriptives_response_type , " confidence_invisible_response_type_descriptives" , tables_dir )
274+ save_anova_results(anova_table_response_type , " confidence_invisible_response_type" , tables_dir )
275+
276+ # create plot
277+ plot_path <- file.path(confidence_dir , " confidence_invisible_response_type.png" )
278+ plot_confidence_interaction(conf_response_type %> %
279+ mutate(is_flanker_error = response_type == " flanker_error" ),
280+ plot_type = " response_type" ,
281+ save_path = plot_path )
282+ }
283+
284+ # === save summary table ===
285+ cat(" \n === saving confidence rating summary tables ===\n " )
286+
287+ # combine all descriptives for summary
288+ all_descriptives <- list ()
289+
290+ if (exists(" descriptives_correctness" )) {
291+ all_descriptives $ visible_correctness <- descriptives_correctness %> %
292+ mutate(analysis = " Visible: Correctness" )
293+ }
294+
295+ if (exists(" descriptives_error_type" )) {
296+ all_descriptives $ visible_error_type <- descriptives_error_type %> %
297+ mutate(analysis = " Visible: Error Type" )
298+ }
299+
300+ if (exists(" descriptives_response_type" )) {
301+ all_descriptives $ invisible_response_type <- descriptives_response_type %> %
302+ mutate(analysis = " Invisible: Response Type" )
303+ }
304+
305+ if (length(all_descriptives ) > 0 ) {
306+ summary_table <- bind_rows(all_descriptives ) %> %
307+ mutate(across(c(mean , sd , se ), ~ round(. , 3 )))
308+
309+ # save as csv
310+ write_csv(summary_table , file.path(tables_dir , " confidence_summary.csv" ))
311+ cat(" summary table saved to confidence_summary.csv\n " )
312+ }
313+
314+ cat(" \n === confidence rating analyses complete ===\n " )
315+ cat(" results saved to:" , confidence_dir , " \n " )
0 commit comments