#Change to your own directory (where you keep the data file) dir = 'C:\\Users\\yoav\\Documents\\bigfiles\\qualtrics.iat\\gal.elinor\\raw' # 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))) } #Read your file here. #df = read.csv(paste(dir, 'Minno IAT_March 5, 2020_11.37.csv',sep = '\\')) df.age = read.csv(paste(dir, 'IATage.csv',sep = '\\')) df.arab = read.csv(paste(dir, 'IATarab.csv',sep = '\\')) df.asia = read.csv(paste(dir, 'iatAsianamer.csv',sep = '\\')) df.dis = read.csv(paste(dir, 'IATdisability.csv',sep = '\\')) df.career = read.csv(paste(dir, 'IATgendercareer.csv',sep = '\\')) df.pres1 = read.csv(paste(dir, 'iatpresident1.csv',sep = '\\')) df.pres2 = read.csv(paste(dir, 'IATpresident2.csv',sep = '\\')) df.rlg = read.csv(paste(dir, 'iatreligon.csv',sep = '\\')) dt.wep = read.csv(paste(dir, 'weaponsIAT_June+29,+2020_20.57.csv',sep = '\\')) dt.weight = read.csv(paste(dir, 'weightIAT_June+29,+2020_20.58.csv',sep = '\\')) names(df.age) df <- rbind(df.age, df.arab, df.asia) ncol(df.age) names(df.age) df.age$IAT df <- rbind(df.age[,c('IAT')], df.arab[,c('IAT')], df.asia[,c('IAT')]) names(df.arab) df.age = read.csv(paste(dir, 'IATage.csv',sep = '\\'))[,c('StartDate','EndDate','IAT')] #Read your file here. #df = read.csv(paste(dir, 'Minno IAT_March 5, 2020_11.37.csv',sep = '\\')) df.age = read.csv(paste(dir, 'IATage.csv',sep = '\\'))[,c('StartDate','EndDate','IAT')] df.arab = read.csv(paste(dir, 'IATarab.csv',sep = '\\'))[,c('StartDate','EndDate','Q7')] df.asia = read.csv(paste(dir, 'iatAsianamer.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] df.dis = read.csv(paste(dir, 'IATdisability.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] df.career = read.csv(paste(dir, 'IATgendercareer.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] df.pres1 = read.csv(paste(dir, 'iatpresident1.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] df.pres2 = read.csv(paste(dir, 'IATpresident2.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] df.rlg = read.csv(paste(dir, 'iatreligon.csv',sep = '\\'))[,c('StartDate','EndDate','Q2')] dt.wep = read.csv(paste(dir, 'weaponsIAT_June+29,+2020_20.57.csv',sep = '\\'))[,c('StartDate','EndDate','Q1')] dt.weight = read.csv(paste(dir, 'weightIAT_June+29,+2020_20.58.csv',sep = '\\'))[,c('StartDate','EndDate','Q1')] theNames <- c('StartDate','EndDate','IAT') df <- rbind(setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.asia, theNames)) View(df) df <- rbind(setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.asia, theNames), setNames(df.dis, theNames), setNames(df.career, theNames), setNames(df.asia, theNames), setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.pres1, theNames), setNames(df.pres2, theNames), setNames(df.rlg, theNames), setNames(dt.wep, theNames), setNames(dt.weight, theNames)) df <- df[which(grepl('block', df$IAT),] which(grepl('block', df$IAT) ) df <- df[which(grepl('block', df$IAT)),] View(df) library(kutils) df$IAT <- mgsub(df$Q3, pattern = c('""'), replacement = c('"')) theNames <- c('StartDate','EndDate','IATraw') df <- rbind(setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.asia, theNames), setNames(df.dis, theNames), setNames(df.career, theNames), setNames(df.asia, theNames), setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.pres1, theNames), setNames(df.pres2, theNames), setNames(df.rlg, theNames), setNames(dt.wep, theNames), setNames(dt.weight, theNames)) df <- df[which(grepl('block', df$IATraw)),] df$IAT <- mgsub(df$IATraw, pattern = c('""'), replacement = c('"')) df2 <- qiat.parse.quoted(df = df, id='ResponseId', data = 'IAT') utils::View(df) df.age = read.csv(paste(dir, 'IATage.csv',sep = '\\'))[,c('StartDate','EndDate', 'ResponseId', 'IAT')] #Read your file here. #df = read.csv(paste(dir, 'Minno IAT_March 5, 2020_11.37.csv',sep = '\\')) df.age = read.csv(paste(dir, 'IATage.csv',sep = '\\'))[,c('StartDate','EndDate', 'ResponseId', 'IAT')] df.arab = read.csv(paste(dir, 'IATarab.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q7')] df.asia = read.csv(paste(dir, 'iatAsianamer.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] df.dis = read.csv(paste(dir, 'IATdisability.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] df.career = read.csv(paste(dir, 'IATgendercareer.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] df.pres1 = read.csv(paste(dir, 'iatpresident1.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] df.pres2 = read.csv(paste(dir, 'IATpresident2.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] df.rlg = read.csv(paste(dir, 'iatreligon.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q2')] dt.wep = read.csv(paste(dir, 'weaponsIAT_June+29,+2020_20.57.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q1')] dt.weight = read.csv(paste(dir, 'weightIAT_June+29,+2020_20.58.csv',sep = '\\'))[,c('StartDate','EndDate','ResponseId', 'Q1')] theNames <- c('StartDate','EndDate','ResponseId', 'IATraw') df <- rbind(setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.asia, theNames), setNames(df.dis, theNames), setNames(df.career, theNames), setNames(df.asia, theNames), setNames(df.age, theNames), setNames(df.arab, theNames), setNames(df.pres1, theNames), setNames(df.pres2, theNames), setNames(df.rlg, theNames), setNames(dt.wep, theNames), setNames(dt.weight, theNames)) df <- df[which(grepl('block', df$IATraw)),] #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$IATraw, pattern = c('""'), replacement = c('"')) #Use Elad's parsing function df2 <- qiat.parse.quoted(df = df, id='ResponseId', data = 'IAT') View(df2) nrow(df2) names(df2) 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) table(iat.raw$comp, iat.raw$cond, exclude=NULL) 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) table(iat.raw$cond, iat.raw$comp, exclude=NULL) #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)),] #Verify that both are numbers (probably, integer) class(iat.raw$rt) class(iat.raw$err) ##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) 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)]) ##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 #Change to your own directory (where you keep the data file) dir = 'C:\\Users\\yoav\\Documents\\bigfiles\\qualtrics.iat\\gal.elinor\\raw' # 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))) } # 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))) } #Read your file here. df.no = read.csv(paste(dir, 'exampleBIAT-BIATnoImpages.csv',sep = '\\')) df.img = read.csv(paste(dir, 'exampleBIATimage-BIATimages.csv',sep = '\\')) View(df.img) View(df.no) df <- rbind(df.no[,c('StartDate','EndDate','ResponseId', 'Q2')], df.img[,c('StartDate','EndDate','ResponseId', 'Q2')]) #We bind the two datasets together, but you're probably going to have only one file df <- rbind(df.no[,c('StartDate','EndDate','ResponseId', 'Q2')], df.img[,c('StartDate','EndDate','ResponseId', 'Q2')]) #Q2 is the question that displayed the IAT and all the IAT data was saved under Q2. #If the text 'block' does not appear in Q2's response, then the IAT data were not saved in that question. Somehow, the IAT was not completed, or perhaps this is from an earlier stage before your IAT was setup correctly. df <- df[which(grepl('block', df$Q2)),] View(df) #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$Q2, pattern = c('""'), replacement = c('"')) #Use Elad's parsing function df2 <- qiat.parse.quoted(df = df, id='ResponseId', data = 'IAT') #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" table(df2$block, exclude=NULL) iat.raw <- df2[which(df2$block > 1),] #Sanity check: need to include only "incompatible" and "compatible" table(iat.raw$comp, exclude=NULL) table(iat.raw$cond, iat.raw$comp, exclude=NULL) View(df) View(iat.raw)