```{r} #Change to your own directory (where you keep the data file) dir = 'C:\\Users\\yoav\\Documents\\bigfiles\\qualtrics.iat' ``` ```{r} # Copied from Elad Zlotnick (from here: https://github.com/eladzlot/minnojs-qiat/blob/master/qiat.R) # Parse csv generated by minnoJS # # @param df a data frame # @param id the column name holding the ids # @param data the column name holding the data (we assume the data holds an array of unnested objects) # # @example # qiat.parse.quoted(df, 'ResponseId', 'Q_47') # qiat.parse(df, ResponseId, Q_47) # # @returns data frame with parsed data, rows with NA or '' are omitted. qiat.parse.quoted = function(df, id, data){ # @TODO does not work? # if (is.factor(df[id])) stop(paste0(data, ' column must not be a factor')) filteredDF = df[df[,data]!='' & !is.na(df[,data]) ,] # parse data -> list of data data frames csvList = lapply(filteredDF[,data], function(str) tryCatch({ read.csv(text=str,stringsAsFactors = FALSE) }, error = function(err){ message('woa there is a malformed csv here') return(NA) } )) #browser() # add id to each data DF mask = which(sapply(csvList,nrow)>0) dataPages = mapply( function(id, df) cbind(id,df), filteredDF[mask,id], csvList[mask], SIMPLIFY = FALSE ) if (!length(dataPages)) { return(data.frame()) } # concat pages do.call(rbind,dataPages) } qiat.parse = function(df, id, data){ qiat.parse.quoted(df, deparse(substitute(id)), deparse(substitute(data))) } ``` ```{r} #Read your file here. #df = read.csv(paste(dir, 'Minno IAT_March 5, 2020_11.37.csv',sep = '\\')) df = read.csv(paste(dir, 'demo gender science IAT_March 9, 2020_10.40.csv',sep = '\\')) ``` ```{r} #The escaping in the data sometimes uses "" which we need to change to " for the parsing. #Note Q3 in my data was the columns that saved the IAT data for each participant. It might have a different name in your data. library(kutils) df$IAT <- mgsub(df$Q3, pattern = c('""'), replacement = c('"')) ``` ```{r} #Use Elad's parsing function df2 <- qiat.parse.quoted(df = df, id='ResponseId', data = 'IAT') ``` ```{r} #Sanity check: see the names of the variables. nrow(df2) names(df2) #If successful, these should be: "id" "block" "trial" "cond" "comp" "type" "cat" "stim" "resp" "err" "rt" "d" "fb" "bOrd" ``` ```{r} #Keep only the critical blocks iat.raw <- df2[which(df2$block %in% c(3,4,6,7)),] #Sanity check: need to include only "incompatible" and "compatible" table(iat.raw$comp, exclude=NULL) #Make sure the 'compatible' trials are indeed what you expected them to be. table(iat.raw$comp, iat.raw$cond, exclude=NULL) ``` ```{r} #The combination of compatibility condition and block number determined the blockName for the IAT scoring function. iat.raw$blockName <- ifelse(iat.raw$comp == 'compatible', ifelse(iat.raw$block %in% c(3,6), "B3", ifelse(iat.raw$block %in% c(4,7), "B4", NA)), ifelse(iat.raw$comp == 'incompatible', ifelse(iat.raw$block %in% c(3,6), "B6", ifelse(iat.raw$block %in% c(4,7), "B7", NA)), NA)) #Make sure you only have B3,B4,B6, and B7 and no NAs. table(iat.raw$blockName, exclude=NULL) #Not supposed to have any NA at this point. So, if you see here, investigate why #(e.g., perhaps some of your data has different cond values than expected, if you changed the cond after running a few participants) iat.raw <- iat.raw[which(!is.na(iat.raw$blockName)),] ``` ```{r} #Verify that both are numbers (probably, integer) class(iat.raw$rt) class(iat.raw$err) ``` ```{r} ##Sanity check. For each participant, we expect a certain number of trials for in each block. ##We will indicate whether the participant has the expected number of trials within each of the critical block. library(doBy) nTrials.long <- summaryBy(formula = err ~ id + blockName, data=iat.raw, FUN = length) library(reshape2) nTrials <- dcast(nTrials.long, id ~ blockName, value.var = 'err.length') #You can change those number if your IAT had different numbers library(dplyr) nTrials <- nTrials %>% mutate(ntrials.ok = case_when( nTrials$B3==20 & nTrials$B4==40 & nTrials$B6==20 & nTrials$B7==40 ~ TRUE, TRUE ~ FALSE )) #If not all are TRUE, then you some participants are missing data table(nTrials$ntrials.ok, exclude=NULL) ``` ```{r} library(IAT) iatscore <- cleanIAT(iat.raw, block_name="blockName", trial_blocks = c("B3", "B4", "B6", "B7"), session_id="id", trial_latency="rt", trial_error = "err", v_error=2, v_extreme=2, v_std=1) #v_error=2 means recode error latency to m+600, v_error=1 mean the standard (onset of stimuli until the correct response is pressed). v_extreme=2(current standard)=delete trial latencies < 400ms. v_std=1 (current standard), block SD is performed including error trials #How many participants were excluded for problematic performance? table(iatscore$SUBEXCL, exclude=NULL) #Summary of those who were not excluded. summary(iatscore$IAT[which(iatscore$SUBEXCL==0)]) ``` ```{r} ##Simple graph library(ggplot2) iatscore$dummy <- '' box_plot <- ggplot(iatscore, aes(x = dummy, y = IAT)) box_plot + geom_boxplot() + geom_dotplot(binaxis = 'y', dotsize = 0.4, stackdir = 'center') + theme_classic() + stat_summary(geom = "point", fun.y = "mean", col = "black", size = 3, shape = 24, fill = "grey") iatscore$dummy <- NULL ``` ```{r} #Get the bord variable block.order1 <- df2[which(!is.na(df2$bOrd) & nchar(df2$bOrd)>0),c('id', 'bOrd')] table(block.order1$bOrd, exclude=TRUE) #Also get the block order condition from the raw data block.order2 <- df2[which(df2$block==3),c('id','cond','comp')] block.order2 <- unique(block.order2) names(block.order2) <- c('id', 'block3Cond', 'block3Comp') #Should be TRUE if all is fine. length(unique(block.order2$id)) == nrow(block.order2) #Should be TRUE if all is fine. nrow(block.order1) == nrow(block.order2) block.order <- merge(block.order1, block.order2, by='id') table(block.order$bOrd, block.order$block3Cond, exclude=NULL) ```