
Code Examples
I have used a variety of coding languages in my research, both for organizing and analyzing data, as well as for designing materials for studies. With the exception of my experience with MatLab—which I first learned from sitting in on two lectures for a programming course—I am almost entirely self-taught. I spent a few hours of my free time each week during my MA and PhD learning how to write and apply code for a variety of purposes. Below are several examples of code that I have written and used in my own work.
SQL
-- Typically I do these pulls for several hundred cases minimum.-- This grabs all the major variables we needed and exports them in one complete table.-- Database and table names have been changed for security reasons.--DROP TABLE #SAMPLECREATE TABLE #SAMPLE (MRN NVARCHAR(7),VISIT NVARCHAR(8),SURG_DT DATE)INSERT INTO #SAMPLEVALUES ('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */'),('/* 7 digit MRN */','/* 8 digit visit number */','/* yyyy-mm-dd */')ALTER TABLE #SAMPLEADD ASA_CLASS NVARCHAR(40) --DB1.SURGICAL_CASE,PT_ZIP VARCHAR(50) --DB2.PATDEMO,PT_CITY VARCHAR(50) --DB2.PATDEMO,PT_STATE VARCHAR(30) --DB2.PATDEMO,DATE_BIRTH DATE --DB2.PATDEMO,SEX VARCHAR(1) --DB2.PATDEMO,NAME_LAST VARCHAR(200) --DB3.PATIENT,NAME_FIRST VARCHAR(200) --DB3.PATIENT,EBL_ML VARCHAR(255),PSYCH_HX NVARCHAR(1),DM NVARCHAR(1),ALCOHOL NVARCHAR(255),ALCOHOL_TEXT NVARCHAR(MAX),TOBACCO NVARCHAR(255),TOBACCO_TEXT NVARCHAR(MAX),SUB_ABUSE NVARCHAR(255),SUB_ABUSE_TEXT NVARCHAR(MAX),BMI NVARCHAR(255),RACE VARCHAR(40),ETHNICITY VARCHAR(40)WITH EBL_AGG AS(SELECT DISTINCT a.MRN,a.VISIT--,SUM(CAST(RESULT_VAL AS INT)) AS EBL_ML,DISP1,DISP2,DISP3,DISP4,RESULT_VAL,EVENT_END_DT_TMFROM #SAMPLE a,DB3.NURSING_DOC bWHERE a.VISIT = b.VISITAND DISP4 LIKE 'EBL in OR (mL)'AND CAST(EVENT_END_DT_TM AS DATE) = SURG_DT),EBL AS(SELECT DISTINCT MRN,VISIT,SUM(CAST(RESULT_VAL AS INT)) AS EBL_MLFROM EBL_AGGGROUP BY MRN,VISIT),DX AS(SELECT DISTINCT a.MRN,a.VISIT,SURG_DT,MAX((CASEWHEN DX_CODE BETWEEN 'F01' AND 'F09.999' THEN '1'WHEN DX_CODE BETWEEN 'F20' AND 'F99' THEN '1'ELSE '0'END)) AS PSYCH_HXFROM #SAMPLE a,DB3.DIAGNOSIS bWHERE LEN(DX_CODE) < '8'AND LEN(DX_CODE) > '2'AND DX_DT_TM <= SURG_DTAND a.MRN = b.MRNGROUP BY a.MRN,a.VISIT,SURG_DT),DIABETUS AS(SELECT DISTINCT a.MRN,a.VISIT,SURG_DT,MAX((CASEWHEN DX_CODE BETWEEN 'E08' AND 'E13.999' THEN '1'ELSE '0'END)) AS DMFROM #SAMPLE a,DB3.DIAGNOSIS bWHERE LEN(DX_CODE) < '8'AND LEN(DX_CODE) > '2'AND DX_DT_TM <= SURG_DTAND a.MRN = b.MRNGROUP BY a.MRN,a.VISIT,SURG_DT),AGG_HIST AS(SELECT DISTINCT b.MRN,CATEGORY,ELEMENT--,RESPONSE,MAX(LAST_UPDATED) AS UPDATEDFROM DB3.SOCIAL_HISTORY a,#SAMPLE bWHERE a.MRN = b.MRNAND CATEGORY IN ('Alcohol', 'Tobacco', 'Substance Abuse')AND ELEMENT = 'Use:'AND LAST_UPDATED <= SURG_DTGROUP BY b.MRN,CATEGORY,ELEMENT),CURRENT_HIST AS(SELECT a.MRN,a.CATEGORY,b.ELEMENT,UPDATED,RESPONSE,DETAILSFROM AGG_HIST a,DB3.SOCIAL_HISTORY bWHERE UPDATED = LAST_UPDATEDAND a.MRN = b.MRNAND a.CATEGORY = b.CATEGORYAND b.ELEMENT = 'Use:'--ORDER BY a.MRN, a.CATEGORY, b.ELEMENT),----------CHANGE CODE BELOW BASED ON WHAT RESPONSES THERE ARE FOR THE CATEGORIES--------SUB_HIST AS(SELECT a.MRN,VISIT,(CASEWHEN (CATEGORY = 'Alcohol'AND RESPONSE IN ('Current', 'Past', 'Never')) THEN RESPONSEELSE ''END) AS ALCOHOL,(CASEWHEN (CATEGORY = 'Alcohol'AND RESPONSE IN ('Current', 'Past', 'Never')) THEN DETAILSELSE ''END) AS ALCOHOL_TEXT,(CASEWHEN (CATEGORY = 'Tobacco'AND RESPONSE IN ('Current', 'Current every day smoker', 'Current some day smoker', 'Former smoker', 'Never smoker', 'Past')) THEN RESPONSEELSE ''END) AS TOBACCO,(CASEWHEN (CATEGORY = 'Tobacco'AND RESPONSE IN ('Current', 'Current every day smoker', 'Current some day smoker', 'Former smoker', 'Never smoker', 'Past')) THEN DETAILSELSE ''END) AS TOBACCO_TEXT,(CASEWHEN (CATEGORY = 'Substance Abuse'AND RESPONSE IN ('Current', 'Past', 'Never')) THEN RESPONSEELSE ''END) AS SUB_ABUSE,(CASEWHEN (CATEGORY = 'Substance Abuse'AND RESPONSE IN ('Current', 'Past', 'Never')) THEN DETAILSELSE ''END) AS SUB_ABUSE_TEXT--INTO SUB_HISTFROM #SAMPLE a,CURRENT_HIST bWHERE a.MRN = b.MRNAND UPDATED <= SURG_DT),BMI AS(SELECT DISTINCT a.MRN,b.VISIT AS SURGERY,a.VISIT AS PRE_VISIT,RESULT_VAL--INTO #BMIFROM DB3.NURSING_DOC a, #SAMPLE bWHERE a.MRN = b.MRNAND a.VISIT <= b.VISITAND EVENT_TITLE_TEXT = 'Body Mass Index'AND RESULT_VAL '0.00'),BMI_VISIT AS(SELECT MRN,SURGERY,MAX(PRE_VISIT) AS PRE_VISIT--INTO #BMI_VISITFROM BMIWHERE PRE_VISIT <= SURGERYGROUP BY SURGERY,MRN),BMI_VAL AS(SELECT a.MRN,a.SURGERY AS VISIT,RESULT_VAL--INTO #BMI_VALFROM BMI_VISIT a, BMI bWHERE a.MRN = b.MRNAND a.SURGERY = b.SURGERYAND a.PRE_VISIT = b.PRE_VISIT)UPDATE #SAMPLESET #SAMPLE.ASA_CLASS = b.ASA_CLASS,#SAMPLE.PT_ZIP = c.PT_ZIP,#SAMPLE.PT_CITY = c.PT_CITY,#SAMPLE.PT_STATE = c.PT_STATE,#SAMPLE.DATE_BIRTH = c.DATE_BIRTH,#SAMPLE.SEX = c.SEX,#SAMPLE.NAME_LAST = d.NAME_LAST,#SAMPLE.NAME_FIRST = d.NAME_FIRST,#SAMPLE.RACE = d.RACE,#SAMPLE.ETHNICITY = d.ETHNICITY,#SAMPLE.EBL_ML = e.EBL_ML,#SAMPLE.PSYCH_HX = f.PSYCH_HX,#SAMPLE.DM = g.DM,#SAMPLE.ALCOHOL = h.ALCOHOL,#SAMPLE.ALCOHOL_TEXT = h.ALCOHOL_TEXT,#SAMPLE.TOBACCO = h.TOBACCO,#SAMPLE.TOBACCO_TEXT = h.TOBACCO_TEXT,#SAMPLE.SUB_ABUSE = h.SUB_ABUSE,#SAMPLE.SUB_ABUSE_TEXT = h.SUB_ABUSE_TEXT,#SAMPLE.BMI = i.RESULT_VALFROM #SAMPLE aLEFT JOIN DB1.SURGICAL_CASE b ON a.MRN = b.MRN AND a.VISIT = b.VISITLEFT JOIN DB2.PATDEMO c ON a.MRN = c.MRNLEFT JOIN DB3.PATIENT d ON a.MRN = d.MRNLEFT JOIN EBL e ON (a.MRN = e.MRN AND a.VISIT = e.VISIT)LEFT JOIN DX f ON (a.MRN = f.MRN AND a.VISIT = f.VISIT AND a.SURG_DT = f.SURG_DT)LEFT JOIN DIABETUS g ON (a.MRN = g.MRN AND a.VISIT = g.VISIT AND a.SURG_DT = g.SURG_DT)LEFT JOIN SUB_HIST h ON (a.MRN = h.MRN AND a.VISIT = h.VISIT)LEFT JOIN BMI_VAL i ON (a.MRN = i.MRN AND a.VISIT = i.VISIT)
R
I use R for nearly all of my data analysis needs. Below is an example of the annotated syntax I made for a colleague so that she could see how to generate the same results in R as in MPlus for modelling indirect effects in a structural model with two latent intermediate variables and a latent outcome variable.
# You will need to install the lavaan and semPlot packages. Install using 'install.packages()'.## NOTE: You only need to install packages once! After that, you only need to reference the library.install.packages("lavaan")install.packages("semPlot")# I tried to set this up so that it could be reused without much modification. The only bits that will# need changing should be the name of the data file and the model specification. As far as I can tell,# everything else is pretty generic.# To format the file for lavaan, I did the same things I would have for Mplus, but then I saved it as a CSV# file instead of a DAT file. Make sure the variable names are saved to the first line of the CSV.# As far as I can tell, there's no limit on how long the file path can be, so you can save the file wherever# you want (and can easily get the file path). I usually save it to my desktop so that I can reuse the code# for setting the file directory. Here's an example of how to set your working directory:getwd()# This will tell you what your current directory is## My default directory is '[1] "C:/Users/droletca/Documents"'## I used the directory from the output, which said it was set to my Documents folder, and modified it so that## it was set to my Desktop ('C:/Users/droletca/Documents' changed to 'C:/Users/droletca/Desktop').## Then I set the working directory to the Desktop using the syntax below.setwd("C:/Users/droletca/Desktop")# After you've set your working directory to the location the has your data file, you can use the syntax# below to import the data into R. Just change "Dance Study_Dancer (FULL)_MPLUS(03.14.2019).csv" to# the name of your data file.myData <-read.csv("Dance Study_Dancer (FULL)_MPLUS(03.14.2019).csv")# To recode missing data values if they were numerically coded## To avoid having missing data included in the analysis, it is easiest be recoded them as 'NA'.## To recode a specific variable, use 'myData$' followed by the variable name.myData[myData == -999] <-NA# Specify the model.## The layout is super similar to Mplus (there is even syntax for converting Mplus syntax to lavaan,## but it doesn't always do a very good job).## - Name paths for mediation or moderation tests by putting the path label in front of the predictor with a '*'## (e.g., 'b1*SAT'). Use the same method for specifying loadings (e.g., '1*SAT').## - Mplus 'by' is '=~' in lavaan.## - Mplus 'on' is '~' in lavaan.## - Mplus 'with' is '~~' in lavaan.## - If there are multiple variables on the right side of '=~', '~', or '~~', they must be connected by '+'.## - Test indirect paths, total effects, and simple slopes by defining parameters (e.g., 'indirect1 := a1 * b1')## As long as the variable names are printed in the top row of your data file, they will be recognized.## NOTE: R syntax is case sensitive! The model won't work if the variable names are not exactly the same## as the names in your data file. Also, make sure you include the last apostrophe when running this syntax!library(lavaan)Dance.model <-'VESTED =~ IMPRTNT + ENJOYSAT =~ ASAT + RLSAT + COMSATFRU =~ AFR + RLFR + COMFRCOMFR ~~ COMSATSOP ~~ SPPSAT ~~ FRUSAT ~ SOP + a1*SPPFRU ~ SOP + SPPVESTED ~ b1*SAT + FRUindirect1 := a1 * b1'# NOTE: For most models, the syntax below can be run without any changes.# Calculate model estimates/coefficients## The syntax below gives estimates that are almost identical to what you would get in Mplus. The only## difference I noted is that the test of the indirect effect is a tad more conservative.## For the standardize coefficients, use the Std.all column.## NOTE: The bootstrapping procedures in R don't appear to be as efficient as the ones in Mplus, so expect## to be waiting approximately 1s for every 10 bootstraps (so 5000 bootstraps would take around 8.33 minutes## or more). The bootstrapping can run in the background while you do other things, but it might delay it a bit.fit <-lavaan(Dance.model,data= myData,auto.var=TRUE,int.ov.free=TRUE,auto.fix.first=TRUE,auto.cov.lv.x=TRUE,se="bootstrap",bootstrap=1000,missing="fiml")# Show model summary and statisticssummary(fit,fit.measures=TRUE,standardize=TRUE,rsquare=TRUE,estimates=TRUE,ci=TRUE)# Path diagram## I added a bunch of stuff to make the diagram look nice, but you could also use 'semPaths(fit)' for## just a basic path model with no loadings.library(semPlot)semPaths(fit,"std","est",style="lisrel",layout="tree2",covAtResiduals=TRUE,residuals=TRUE,shapeLat="ellipse",shapeMan="rectangle",nCharNodes=4,color=list(lat =rgb(255,253,71,maxColorValue=255),# Block to remove colorman=rgb(155,253,175,maxColorValue=255)),# Block to remove colormar=c(5,5,5,5),fade=FALSE,weighted=FALSE,edge.color="black",edge.label.cex=0.7,label.norm="OOO",label.prop=0.7,intercepts=FALSE,thresholds=FALSE,rotation=1,)
Excel Macros
For a study I conducted with Hafer, Davis, and Segalowitz (2019), I had to find and organize the cells for reaction times to specific lines in each of 120 stories. The initial data came from E-Prime and I wrote an excel macro to organize and label the cells we needed for analysis out of the millions of other cells in the dataset that were not needed.
SubfullMacro()'Before running this macro, check to make sure the highest row value matches the total number of'rows in the file (current highest row value is 13911).'Also check that the sheet name in the macro matches the sheet name in the file (participants 1-10).''This part edits the file so that it is compatible with the file for which the original code was written.Sheets("participants 1-10").SelectSheets("participants 1-10").Name = "exported merged file"Rows("1:1").SelectSelection.Delete Shift:=xlUpColumns("F:F").SelectSelection.Insert Shift:=xlToRightRange("F1").SelectActiveCell.FormulaR1C1 = "Delay"Range("F2").SelectActiveCell.FormulaR1C1 = "150"Range("F2").SelectSelection.CopyRange("F3").SelectActiveWindow.ScrollRow = 13888Range("F3:F13911").SelectActiveSheet.Paste'This part just copies the text from each story line so I can make sure nothing gets shifted up or down.Columns("D:D").SelectApplication.CutCopyMode = FalseSelection.Insert Shift:=xlToRightColumns("YP:YP").SelectSelection.CopyColumns("D:D").SelectActiveSheet.Paste'This next part collapses the empty cells.Range("AE1:YP13911").SpecialCells(xlCellTypeBlanks).Delete Shift:=xlToLeft'Next, it deletes all the rows for practice trials.Columns("W:W").SelectSelection.AutoFilterActiveSheet.Range("$W$1:$W$13911").AutoFilter Field:=1, Criteria1:= _"PracticeProc"Range("A2:AV13911").SpecialCells(xlCellTypeVisible).Delete Shift:=xlShiftUpColumns("W:W").SelectSelection.AutoFilter'One of the columns was really wide, so I adjusted the size.Columns("BC:BC").EntireColumn.AutoFitColumns("AL:AL").Select'This next part gets rid of some of the information we don’t need (e.g., onset delay). For whatever reason, the'columns for block 3 don’t align with other blocks (onset delay and onset time columns are missing).Selection.AutoFilterActiveSheet.Range("$AL$1:$AL$13911").AutoFilter Field:=1, Criteria1:=Array( _"1", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", _"29", "30", "31", "32", "Block1", "Block10", "Block11", "Block12", "Block13", "Block14", _"Block15", "Block16", "Block17", "Block18", "Block19", "Block2", "Block20", "Block4", _"Block5", "Block6", "Block7", "Block8", "Block9", "="), Operator:=xlFilterValuesRange("AX1:BA13911").SelectRange("AX1:BA13911").SpecialCells(xlCellTypeVisible).ClearContentsSelection.AutoFilterRange("AX2:BD13911").SpecialCells(xlCellTypeBlanks).Delete Shift:=xlToLeftRange("AX1:YP1").ClearContents'The next part deletes the rows containing responses to the questions.Columns("AJ:AJ").SelectSelection.AutoFilterActiveSheet.Range("$AJ$1:$AJ$13911").AutoFilter Field:=1, Criteria1:=Array( _"a", "b", "c", "d", "e", "="), Operator:=xlFilterValuesRange("A2:AZ13911").SpecialCells(xlCellTypeVisible).Delete Shift:=xlShiftUpSelection.AutoFilterColumns("AI:AI").SelectSelection.AutoFilterActiveSheet.Range("$AI$1:$AI$13911").AutoFilter Field:=1, Criteria1:=Array( _"Q12", "="), Operator:=xlFilterValuesRange("A2:AZ13911").SpecialCells(xlCellTypeVisible).Delete Shift:=xlShiftUpSelection.AutoFilterColumns("AQ:AW").Select'Next, it deletes any remaining rows that we don’t need (e.g., info about the version of e-prime).Range("AW1").ActivateSelection.Delete Shift:=xlToLeftColumns("AP:AP").SelectSelection.Delete Shift:=xlToLeftColumns("AJ:AK").SelectSelection.Delete Shift:=xlToLeftColumns("AE:AH").SelectSelection.Delete Shift:=xlToLeftColumns("Y:AC").SelectRange("AC1").ActivateSelection.Delete Shift:=xlToLeftColumns("W:X").SelectRange("X1").ActivateSelection.Delete Shift:=xlToLeftColumns("S:V").SelectRange("V1").ActivateSelection.Delete Shift:=xlToLeftColumns("A:A").SelectSelection.Delete Shift:=xlToLeftColumns("D:Q").SelectSelection.Delete Shift:=xlToLeftRange("A2").Select'Next, it renames each of the columns.Range("C1").SelectActiveCell.FormulaR1C1 = "StoryText"Range("D1").SelectActiveCell.FormulaR1C1 = "Set"Range("E1").SelectActiveCell.FormulaR1C1 = "StoryNum"Range("F1").SelectActiveCell.FormulaR1C1 = "Block"Range("H1").SelectActiveCell.FormulaR1C1 = "FullStory"Range("I1").SelectActiveCell.FormulaR1C1 = "LineNum"Range("J1").SelectActiveCell.FormulaR1C1 = "RT"Range("K1").SelectActiveCell.FormulaR1C1 = "RTTime"Range("L1").SelectActiveCell.FormulaR1C1 = "StoryText2"Columns("G:G").SelectSelection.Delete Shift:=xlToLeftRange("A2").Select'This next part deletes the lines containing ‘x’.Columns("K:K").SelectSelection.AutoFilterActiveSheet.Range("$K$1:$K$13911").AutoFilter Field:=1, Criteria1:="+"Range("A2:K13911").SpecialCells(xlCellTypeVisible).Delete Shift:=xlShiftUpSelection.AutoFilter'This next part isolates the lines for the outcomes, copies them to a new sheet, and deletes the first sheet.Columns("K:K").SelectSelection.AutoFilterActiveSheet.Range("$K$1:$K$13911").AutoFilter Field:=1, Criteria1:=Array( _"a divorce.", "a flat tire.", "a great job.", "a pay cut.", "a present.", _"a relaxing vacation.", "a traffic jam.", "break up.", "contracted mono.", "couldn't sleep.", _"coworker he disliked.", "coworker she disliked.", "day off work.", "developed an allergy.", "flight was cancelled.", _"food poisoning.", "found $20.", "free baseball tickets.", "free coffee.", "free iPad.", _"got lost.", "had been promoted.", "he fell.", "he won.", "her favourite restaurant.", _"his favourite restaurant.", "it was missing.", "locked out.", "nice weather.", "on a date.", _"on sale.", "perfect parking spot.", "power outage.", "radiator overheated.", "receive $500.", _"she fell.", "spilled her coffee.", "sprained ankle.", "stayed dry.", "was complimented.", _"was complimented.", "was lost.", "was upgraded.", "were lost.", "="), Operator:=xlFilterValuesRange("A1:K13911").SpecialCells(xlCellTypeVisible).CopySheets.Add Type:=xlWorksheetActiveSheet.Name = "outcomesOnly"Sheets("outcomesOnly").SelectActiveSheet.PasteSheets("exported merged file").SelectColumns("K:K").SelectSelection.AutoFilterSheets("exported merged file").SelectActiveWindow.SelectedSheets.DeleteSheets("outcomesOnly").SelectEnd Sub
MatLab
My first introduction to programming was through MatLab. This program helped me to understand syntax structure for a variety of coding languages. The example below was used in conjunction with the Excel macro from the previous section. Once the necessary cells were organized into a csv file, I used MatLab to further arrange and label the data for analysis in SPSS.
%% ADD LABELS FUNCTION %%% All you need to do to use this script is answer the two questions it asks% at the beginning.% NOTE #1: You must have the file containing the data saved to the current% folder in order to import the file.% NOTE #2: Make sure you know the full name of the file, including the file% extension (e.g., exported_data.xlsx)% NOTE #3: Finally, make sure you know the name of the sheet within the% excel file that contains the data.% The file will be saved as 'FinalData.csv' in the current folder.functionaddLabels()input('Make sure the file is saved to the workspace, then hit "enter"');fid = input('What is the name of the file you want to open? ','s');sheet = input('What sheet contains the data? ','s');[~, ~, outcomes] = xlsread(fid, sheet);outcomes = outcomes(2:end,:);outcomes(cellfun(@(x) ~isempty(x) && isnumeric(x) && isnan(x),outcomes)) = {''};[totalrows,totalcolumns]=size(outcomes);row = 1;whilerow <= totalrows;story = outcomes{row, 5};ifstrcmp(outcomes(row,6),'Block1');ifstory == 1;outcomes(row,12) = {36};outcomes(row,13) = {'3d'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {79};outcomes(row,13) = {'11c'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {2};outcomes(row,13) = {'1a'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {73};outcomes(row,13) = {'11a'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {109};outcomes(row,13) = {'15a'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {25} ;outcomes(row,13) = {'3a'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block2');ifstory == 1;outcomes(row,12) = {100};outcomes(row,13) = {'14b'};outcomes(row,14) = {'Deserved'};elseifstory == 2;outcomes(row,12) = {28} ;outcomes(row,13) = {'3b'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {98} ;outcomes(row,13) = {'14a'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {24} ;outcomes(row,13) = {'2d'};outcomes(row,14) = {'Control'};elseifstory == 5;outcomes(row,12) = {68} ;outcomes(row,13) = {'10c'};outcomes(row,14) = {'Undeserved'};elseifstory == 6;outcomes(row,12) = {4};outcomes(row,13) = {'1b'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block3');ifstory == 1;outcomes(row,12) = {117};outcomes(row,13) = {'15c'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {108};outcomes(row,13) = {'14d'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {6};outcomes(row,13) = {'1b'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {48};outcomes(row,13) = {'4d'};outcomes(row,14) = {'Control'};elseifstory == 5;outcomes(row,12) = {42};outcomes(row,13) = {'4b'};outcomes(row,14) = {'Control'};elseifstory == 6;outcomes(row,12) = {43};outcomes(row,13) = {'4c'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block4');ifstory == 1;outcomes(row,12) = {114};outcomes(row,13) = {'15b'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {1};outcomes(row,13) = {'1a'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {57};outcomes(row,13) = {'8c'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {91};outcomes(row,13) = {'12c'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {102};outcomes(row,13) = {'14b'};outcomes(row,14) = {'Control'};elseifstory == 6;outcomes(row,12) = {32};outcomes(row,13) = {'3c'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block5');ifstory == 1;outcomes(row,12) = {69} ;outcomes(row,13) = {'10c'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {5};outcomes(row,13) = {'1b'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {12};outcomes(row,13) = {'1d'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {37};outcomes(row,13) = {'4a'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {118};outcomes(row,13) = {'15d'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {112};outcomes(row,13) = {'15b'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block6');ifstory == 1;outcomes(row,12) = {77};outcomes(row,13) = {'11b'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {111};outcomes(row,13) = {'15a'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {120};outcomes(row,13) = {'15d'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {23};outcomes(row,13) = {'2d'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {40};outcomes(row,13) = {'4b'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {50};outcomes(row,13) = {'8a'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block7');ifstory == 1;outcomes(row,12) = {71};outcomes(row,13) = {'10d'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {34};outcomes(row,13) = {'3d'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {97};outcomes(row,13) = {'14a'};outcomes(row,14) = {'Deserved'};elseifstory == 4;outcomes(row,12) = {62};outcomes(row,13) = {'10a'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {94};outcomes(row,13) = {'12d'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {10};outcomes(row,13) = {'1d'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block8');ifstory == 1;outcomes(row,12) = {39};outcomes(row,13) = {'4a'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {74};outcomes(row,13) = {'11a'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {51};outcomes(row,13) = {'8a'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {7};outcomes(row,13) = {'1c'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {90};outcomes(row,13) = {'12b'};outcomes(row,14) = {'Control'};elseifstory == 6;outcomes(row,12) = {20};outcomes(row,13) = {'2c'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block9');ifstory == 1;outcomes(row,12) = {110};outcomes(row,13) = {'15a'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {107};outcomes(row,13) = {'14d'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {64};outcomes(row,13) = {'10b'};outcomes(row,14) = {'Deserved'};elseifstory == 4;outcomes(row,12) = {81};outcomes(row,13) = {'11c'};outcomes(row,14) = {'Control'};elseifstory == 5;outcomes(row,12) = {76};outcomes(row,13) = {'11b'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {70};outcomes(row,13) = {'10d'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block10');ifstory == 1;outcomes(row,12) = {115};outcomes(row,13) = {'15c'};outcomes(row,14) = {'Deserved'};elseifstory == 2;outcomes(row,12) = {85};outcomes(row,13) = {'12a'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {75};outcomes(row,13) = {'11a'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {13};outcomes(row,13) = {'2a'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {78};outcomes(row,13) = {'11b'};outcomes(row,14) = {'Control'};elseifstory == 6;outcomes(row,12) = {67};outcomes(row,13) = {'10c'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block11');ifstory == 1;outcomes(row,12) = {19};outcomes(row,13) = {'2c'};outcomes(row,14) = {'Deserved'};elseifstory == 2;outcomes(row,12) = {66};outcomes(row,13) = {'10b'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {93};outcomes(row,13) = {'12c'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {14};outcomes(row,13) = {'2a'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {11};outcomes(row,13) = {'1d'};outcomes(row,14) = {'Undeserved'};elseifstory == 6;outcomes(row,12) = {41};outcomes(row,13) = {'4b'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block12');ifstory == 1;outcomes(row,12) = {46};outcomes(row,13) = {'4d'};outcomes(row,14) = {'Deserved'};elseifstory == 2;outcomes(row,12) = {31};outcomes(row,13) = {'3c'};outcomes(row,14) = {'Deserved'};elseifstory == 3;outcomes(row,12) = {113};outcomes(row,13) = {'15b'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {53};outcomes(row,13) = {'8b'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {84};outcomes(row,13) = {'11d'};outcomes(row,14) = {'Control'};elseifstory == 6;outcomes(row,12) = {15};outcomes(row,13) = {'2a'};outcomes(row,14) = {'Control'};endelseifstrcmp(outcomes(row,6),'Block13');ifstory == 1;outcomes(row,12) = {88};outcomes(row,13) = {'12b'};outcomes(row,14) = {'Deserved'};elseifstory == 2;outcomes(row,12) = {92};outcomes(row,13) = {'12c'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {95};outcomes(row,13) = {'12d'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {55};outcomes(row,13) = {'8c'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {44};outcomes(row,13) = {'4c'};outcomes(row,14) = {'Undeserved'};elseifstory == 6;outcomes(row,12) = {38};outcomes(row,13) = {'4a'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block14');ifstory == 1;outcomes(row,12) = {30};outcomes(row,13) = {'3b'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {17};outcomes(row,13) = {'2b'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {60};outcomes(row,13) = {'8d'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {26};outcomes(row,13) = {'3a'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {56};outcomes(row,13) = {'8c'};outcomes(row,14) = {'Undeserved'};elseifstory == 6;outcomes(row,12) = {61};outcomes(row,13) = {'10a'};outcomes(row,14) = {'Deserved'};endelseifstrcmp(outcomes(row,6),'Block15');ifstory == 1;outcomes(row,12) = {54};outcomes(row,13) = {'8b'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {21};outcomes(row,13) = {'2c'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {16};outcomes(row,13) = {'2b'};outcomes(row,14) = {'Deserved'};elseifstory == 4;outcomes(row,12) = {104};outcomes(row,13) = {'14c'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {49};outcomes(row,13) = {'8a'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {63};outcomes(row,13) = {'10a'};outcomes(row,14) = {'Control'};endelseifstrcmp(outcomes(row,6),'Block16');ifstory == 1;outcomes(row,12) = {89};outcomes(row,13) = {'12b'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {105};outcomes(row,13) = {'14c'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {58};outcomes(row,13) = {'8d'};outcomes(row,14) = {'Deserved'};elseifstory == 4;outcomes(row,12) = {86};outcomes(row,13) = {'12a'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {52};outcomes(row,13) = {'8b'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {119};outcomes(row,13) = {'15d'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block17');ifstory == 1;outcomes(row,12) = {8};outcomes(row,13) = {'1c'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {59};outcomes(row,13) = {'8d'};outcomes(row,14) = {'Undeserved'};elseifstory == 3;outcomes(row,12) = {72};outcomes(row,13) = {'10d'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {101};outcomes(row,13) = {'14b'};outcomes(row,14) = {'Undeserved'};elseifstory == 5;outcomes(row,12) = {83};outcomes(row,13) = {'11d'};outcomes(row,14) = {'Undeserved'};elseifstory == 6;outcomes(row,12) = {3};outcomes(row,13) = {'1a'};outcomes(row,14) = {'Control'};endelseifstrcmp(outcomes(row,6),'Block18');ifstory == 1;outcomes(row,12) = {18};outcomes(row,13) = {'2b'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {45};outcomes(row,13) = {'4c'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {65};outcomes(row,13) = {'10b'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {82};outcomes(row,13) = {'11d'};outcomes(row,14) = {'Deserved'};elseifstory == 5;outcomes(row,12) = {103};outcomes(row,13) = {'14c'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {35};outcomes(row,13) = {'3d'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block19');ifstory == 1;outcomes(row,12) = {96};outcomes(row,13) = {'12d'};outcomes(row,14) = {'Control'};elseifstory == 2;outcomes(row,12) = {27};outcomes(row,13) = {'3a'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {33};outcomes(row,13) = {'3c'};outcomes(row,14) = {'Control'};elseifstory == 4;outcomes(row,12) = {99};outcomes(row,13) = {'14a'};outcomes(row,14) = {'Control'};elseifstory == 5;outcomes(row,12) = {106};outcomes(row,13) = {'14d'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {116};outcomes(row,13) = {'15c'};outcomes(row,14) = {'Undeserved'};endelseifstrcmp(outcomes(row,6),'Block20');ifstory == 1;outcomes(row,12) = {47};outcomes(row,13) = {'4d'};outcomes(row,14) = {'Undeserved'};elseifstory == 2;outcomes(row,12) = {9};outcomes(row,13) = {'1c'};outcomes(row,14) = {'Control'};elseifstory == 3;outcomes(row,12) = {29};outcomes(row,13) = {'3b'};outcomes(row,14) = {'Undeserved'};elseifstory == 4;outcomes(row,12) = {87};outcomes(row,13) = {'12a'};outcomes(row,14) = {'Control'};elseifstory == 5;outcomes(row,12) = {22};outcomes(row,13) = {'2d'};outcomes(row,14) = {'Deserved'};elseifstory == 6;outcomes(row,12) = {80};outcomes(row,13) = {'11c'};outcomes(row,14) = {'Undeserved'};endendrow = row + 1;endheader = {'Subject' 'Session' 'StoryText' 'Set' 'StoryNum' 'Block' 'FullStory' 'LineNum' 'RT' 'RTTime' 'StoryText2' 'TotalStoryNum' 'StoryGroup' 'StoryType'};finalDataRows = totalrows + 1;finalData(1,[1:14])=header(1,[1:14]);finalData([2:finalDataRows],[1:14])=outcomes([1:totalrows],[1:14]);finalData(:,7)=[];T = table(finalData);writetable(T,'FinalData.csv','Delimiter',',');end
SPSS Macros
My initial data analysis training was done in SPSS. After more than five years of using the menus and syntax commands for data analysis, I started developing macros for preliminary data cleaning steps. I use the macros shown below to cut down on the amount of time I spend identifying and dealing with both multivariate and univariate outliers.
*These macros and syntax below winsorize outliers, identify multivariate outliers, and then create a new dataset excluding the multivariate outliers.*This is how I winsorized (all of the steps were done in the winsorizing macro below):1. Take absolute values of all z-scores2. Rank the absolute vaules from highest (1) to lowest3. Find the rank for the highest absolute value that is below the cut-off (in this example, 3)4. Use the following formula to calculate the winsorized z-scores (NOTE: if the original z-score was negative, be sure to multiply the final value by -1):((3-limit)/rank limit)*distance+limitlimit = highest absolute value below 3rank limit = the rank associated with the limit valuedistance = rank limit - rank of the z-score for the outlier5. Use the new z-scores to compute new values for the outliers (z*SD+M).*This method ensures that individual scores maintain their relative position in the distribution.DEFINEwinsorizing (vars = !CHAREND('/') / cut = !CMDEND)PRESERVE.SET RESULTS OFF ERRORS OFF.!DO !i !IN (!vars)COMPUTE H = !cut.COMPUTE L = H*-1.EXECUTE.DESCRIPTIVES VARIABLES = !i /SAVE.COMPUTE Z = !CONCAT("Z",!i).EXECUTE.COMPUTE AZ = ABS(Z).EXECUTE.RANK VARIABLES=AZ (D) /RANK into RAZ /PRINT=YES /TIES=LOW.IF AZ LT H RAZ2 = RAZ.IF AZ LT H AZ2 = AZ.EXECUTE.AGGREGATE /OUTFILE=* MODE=ADDVARIABLES OVERWRITE=YES /M=MEAN(!i) /S=SD(!i) /rankLimit = MIN(RAZ2) /limit = MAX(AZ2).COMPUTE !CONCAT("wZ",!i) = Z.IF Z GE H !CONCAT("wZ",!i) = ((H - limit)/rankLimit)*(rankLimit - RAZ) + limit.IF Z LE L !CONCAT("wZ",!i) = (((H - limit)/rankLimit)*(rankLimit - RAZ) + limit)*(-1).EXECUTE.IF AZ LT H !CONCAT("w",!i) = !i.IF AZ GE H !CONCAT("w",!i) = M + S*!CONCAT("wZ",!i).EXECUTE.DELETE VARIABLES Z AZ RAZ RAZ2 AZ2 M S rankLimit limit H L.EXECUTE.!DOENDRESTORE.!ENDDEFINE.*Use the compute statement below to set the z-score cut-off.COMPUTEval = 3.EXECUTE.*Use the syntax below to call the winsorizing macro.winsorizing vars = X Y Z / cut = val./*The varaibles the macro returns are the Z-score for the original variable (Z), the winsorized Z-score (wZ), and the winsorized value (w).DELETE VARIABLESval.EXECUTE.*Counting univariate outliers.DEFINEcountOutliers (vars = !CMDEND)!DO !i !IN (!vars)IF !CONCAT("Z",!i) GE 3 OR !CONCAT("Z",!i) LE -3 !CONCAT("O",!i) = 1.EXECUTE.!DOEND!ENDDEFINE.countOutliers vars = X Y Z.*I then screened for multivariate outliers using the criteria described by Tabachnick and Fidell (2007):if the proportion of Mahalanobis Distance scores that fall below a given score is less than .001, then that score is considered a multivariate outlier.DEFINEmultivariate (dv = !CHAREND('/') / iv = !CHAREND('/') / ivNUM = !CHAREND('/') / type = !CHAREND('/'))***MACRO NOTES****dv: list of outcome variables*iv: list of predictor variables*ivNUM: the number of predictor variables*type: 1 = original, 2 = winsorized data (univariate), 3 = data without univariate outliers, 4 = data without multivariate outliers*Make sure you end each of the macro components with a '/'.*For example, if you have 2 predictors and 2 mediators, and you are running the macro on the original data, then the macro should look like this:*multivariate dv = outcomes / iv = predictors / ivNUM = 2 / type = 1. (Check this...number of predictors seems wrong).PRESERVE.SET RESULTS OFF ERRORS OFF.!DO !i !IN (!dv)REGRESSION/MISSING LISTWISE/CRITERIA=PIN(.05) POUT(.10)/NOORIGIN/DEPENDENT !i/METHOD=ENTER !iv/SAVE MAHAL.COMPUTE p_MAH_1 = 1 - cdf.chisq(MAH_1,!ivNUM).COMPUTE !CONCAT("mv.",!i,!type) = p_MAH_1.EXECUTE.IF !CONCAT("mv.",!i,!type) LT .001 !CONCAT("m0.",!i,!type) = 1.EXECUTE.DELETE VARIABLES p_MAH_1 MAH_1.EXECUTE.!DOENDRESTORE.!ENDDEFINE.*The syntax below screens for multivariate outliers using unwinsorized variables.multivariate dv = wY / iv = wX wZ / ivNUM = 2 / type = 2.*Only 4 multivariate outliers.*Creating dataset without multivariate outliers.DATASET COPYnoMV.DATASET ACTIVATEnoMV.FILTEROFF.USEALL.SELECT IF(MISSING(m0.wY)).EXECUTE.
MPlus
My initial training in SEM and path analysis was done using MPlus. I have used this program to analyze a variety of complex models, including moderation with latent factors (see Drolet & Drolet, 2019). The code below is for a recent project where we had to use WLSMV estimation to examine indirect effects of continuous predictors on a binary outcome. Unlike most other models I have run in MPlus, this model involved the use of WRMR (instead of SRMR) as an indicator of model fit. I also had to use different methods than for ML models for declaring indirect effects and getting Chi-square difference tests to compare models.
title:BinaryOutcomeModeldata:File = /Users/carolinedrolet/Desktop/KeeperData2.dat;variable:Names = IDCulcompAttitudeNormPBCIntentWantFITC_GvTLC_LvTLC_TGvTL;Usevariables =CulcompAttitudeNormPBCIntentWantFITC_GvTLC_LvTLC_TGvTL;categorical = WantFIT;Missing AreCulcompAttitudeNormPBCIntentWantFITC_GvTLC_LvTLC_TGvTL(-999);analysis:ESTIMATOR = WLSMV;!difftest = mydiff.dat;BOOTSTRAP=10000;model:Attitude on Culcomp(a1)C_GvTLC_LvTLC_TGvTL;Norm on Culcomp(a2)C_GvTLC_LvTLC_TGvTL;PBC on Culcomp(a3)C_GvTLC_LvTLC_TGvTL;Intent on Culcomp(a4)!Culcomp@0Attitude(b1)Norm(b2)PBC(b3)C_GvTLC_LvTLC_TGvTL;WantFIT on!Culcomp@0!CulcompIntent(b4)!PBC@0!PBCC_GvTLC_LvTLC_TGvTL;Attitude with Norm PBC;Norm with PBC;model constraint:new (ccEND);ccEND = a4*b4;new (attEND);attEND = a1*b1*b4;new (normEND);normEND = a2*b2*b4;!savedata:!difftest is mydiff.dat;output:SAMPSTAT STANDARDIZED CINTERVAL(BCBOOTSTRAP);
HTML, CSS, and javascript
My greatest coding undertaking to date was my creation of a statistics practice website for undergraduate psychology students (statisticspractice.ca). The entire website was built from scratch using a combination of html, CSS, and javascript. For each task, data are randomly generated each time the page loads, providing a seemingly infinite number of unique practice questions. The text entry boxes provide immediate feedback about whether answers are correct or not, and students can also click “Show Answers” to see the solutions if they get stuck. There is also a calculator in the corner so that students can practice on their phones without having to switch between the browser and the calculator app. Much of the development across versions of the website was based on student feedback, helping to make the experience as accessible to them as possible. We also found that students who performed poorly on the first exam and who used the online questions to study for the next exam scored higher than those who performed poorly on the first exam but who did not use the online questions.
In addition to my stats practice website, I also developed custom html, CSS, and javascript for use in Qualtrics and MTurk studies. Below is an example of a function I wrote for a colleague who was running a reaction-time study that involved a Stroop task. Because the reaction-time measurements were reliant on key presses, it was important that participants were not completing the study on a mobile device. The function that I wrote would check whether they were on a mobile device and, if they were, would tell them they could not take the study before sending them back to the list of available hits. I have also written versions of this code for use on Qualtrics, so that participants can save their progress and then continue the study from their computer.
<!DOCTYPE html><html><bodyonload="detectDevice()">Nothing should happen unless the person is on a mobile device.If they are on a mobile device, the script tells them that they cannotcomplete the survey on a mobile device and takes them back to thelist of available HITs on Mturk.<script>functiondetectDevice(){varz =navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i);if(z==null) {}else{alert("You cannot complete this survey on a mobile device");location.replace("https://www.mturk.com/mturk/findhits?match=false");}}</script></body></html>