In this document we will be taking a look at creating stimlists for Stekic, Nielsen, & Kovic
Note that this is the basic version of this markdown file- the full version will have a function call and produce multiple stimlists, for all 9 experimental conditions
This experiment will be an extension of the protocol use by Lupyan et al. (2007)
In a previous script, we went from a large number of image seeds down to a set of 40 total images- 20 jagged and 20 curvy.
The data for these files has been saved as a .csv called “ImageStims”, so we have to start by loading that in here
ImageStims <- read.csv("F:/Experiments/Collaborations/Stekic et al/Figures/ChosenImages.csv")
Lupyan’s previous work used on a few conditions - these were informative, but not as informative as we would like them to be
So we have conceived of 9 Conditions, but it’s not a totally crossed design (it’s a 2(Category label vs. Systematic individual label) x 3 (Congruent vs. Incongruent vs. Conventional) + 3 (Arbitrary Halfhalf, Arbitrary Full, and No Names)) design
1- Category Label - Congruent 2- Category Label - Incongruent 3- Category Label - Arbitrary
4- Systematic Label - Congruent 5- Systematic Label - Incongruent 6- Systematic Label - Conventional
7- Arbitrary Label (halfhalf) 8- Arbitrary Label (fully)
9- No Labels
All labels will be cVcV bisyllables.
Broadly, there are a total of 4 kinds of labels to be created
Curvy Labels Jagged Labels Conventional Labels I Conventional Labels II
To create these words we need sets of phonemes
Minimally we need 8 consonants and 4 vowels, but 8 vowels may be best (as in Nielsen, 2016).
However I understand that Serbian only has 5 basic vowels, so we may need to make due!
SonorantCons <- c('m', 'n', 'l')
PlosiveCons <- c('p', 't', 'k')
Conv1Cons <- c('f', 'v', 'sh')
Conv2Cons <- c('s', 'z', 'h')
Now we want to take all permutations of our consonant sets and vowel sets to produce the sets of syllables that we will need for the experiment
Vowels <- c("a", 'a:')
########
PlosiveSyll1 <- as.vector(outer(PlosiveCons[c(1,2)], Vowels, paste, sep=""))
PlosiveSyll2 <- as.vector(outer(PlosiveCons[c(1,3)], Vowels, paste, sep=""))
PlosiveSyll3 <- as.vector(outer(PlosiveCons[c(2,3)], Vowels[1], paste, sep=""))
PlosiveWords12 <- as.vector(outer(PlosiveSyll1, PlosiveSyll2, paste, sep=''))
PlosiveWords <- as.vector(outer(PlosiveWords12, PlosiveSyll3, paste, sep=''))
PlosiveWords
## [1] "papata" "tapata" "pa:pata" "ta:pata" "pakata" "takata"
## [7] "pa:kata" "ta:kata" "papa:ta" "tapa:ta" "pa:pa:ta" "ta:pa:ta"
## [13] "paka:ta" "taka:ta" "pa:ka:ta" "ta:ka:ta" "papaka" "tapaka"
## [19] "pa:paka" "ta:paka" "pakaka" "takaka" "pa:kaka" "ta:kaka"
## [25] "papa:ka" "tapa:ka" "pa:pa:ka" "ta:pa:ka" "paka:ka" "taka:ka"
## [31] "pa:ka:ka" "ta:ka:ka"
###############
SonorantSyll1 <- as.vector(outer(SonorantCons[c(1,2)], Vowels, paste, sep=""))
SonorantSyll2 <- as.vector(outer(SonorantCons[c(1,3)], Vowels, paste, sep=""))
SonorantSyll3 <- as.vector(outer(SonorantCons[c(2,3)], Vowels[1], paste, sep=""))
SonorantWords12 <- as.vector(outer(SonorantSyll1, SonorantSyll2, paste, sep=''))
SonorantWords <- as.vector(outer(SonorantWords12, SonorantSyll3, paste, sep=''))
SonorantWords
## [1] "mamana" "namana" "ma:mana" "na:mana" "malana" "nalana"
## [7] "ma:lana" "na:lana" "mama:na" "nama:na" "ma:ma:na" "na:ma:na"
## [13] "mala:na" "nala:na" "ma:la:na" "na:la:na" "mamala" "namala"
## [19] "ma:mala" "na:mala" "malala" "nalala" "ma:lala" "na:lala"
## [25] "mama:la" "nama:la" "ma:ma:la" "na:ma:la" "mala:la" "nala:la"
## [31] "ma:la:la" "na:la:la"
################
Conv1Syll1 <- as.vector(outer(Conv1Cons[c(1,2)], Vowels, paste, sep=""))
Conv1Syll2 <- as.vector(outer(Conv1Cons[c(1,3)], Vowels, paste, sep=""))
Conv1Syll3 <- as.vector(outer(Conv1Cons[c(2,3)], Vowels[1], paste, sep=""))
Conv1Words12 <- as.vector(outer(Conv1Syll1, Conv1Syll2, paste, sep=''))
Conv1Words <- as.vector(outer(Conv1Words12, Conv1Syll3, paste, sep=''))
Conv1Words
## [1] "fafava" "vafava" "fa:fava" "va:fava" "fashava"
## [6] "vashava" "fa:shava" "va:shava" "fafa:va" "vafa:va"
## [11] "fa:fa:va" "va:fa:va" "fasha:va" "vasha:va" "fa:sha:va"
## [16] "va:sha:va" "fafasha" "vafasha" "fa:fasha" "va:fasha"
## [21] "fashasha" "vashasha" "fa:shasha" "va:shasha" "fafa:sha"
## [26] "vafa:sha" "fa:fa:sha" "va:fa:sha" "fasha:sha" "vasha:sha"
## [31] "fa:sha:sha" "va:sha:sha"
################
Conv2Syll1 <- as.vector(outer(Conv2Cons[c(1,2)], Vowels, paste, sep=""))
Conv2Syll2 <- as.vector(outer(Conv2Cons[c(1,3)], Vowels, paste, sep=""))
Conv2Syll3 <- as.vector(outer(Conv2Cons[c(2,3)], Vowels[1], paste, sep=""))
Conv2Words12 <- as.vector(outer(Conv2Syll1, Conv2Syll2, paste, sep=''))
Conv2Words <- as.vector(outer(Conv2Words12, Conv2Syll3, paste, sep=''))
Conv2Words
## [1] "sasaza" "zasaza" "sa:saza" "za:saza" "sahaza" "zahaza"
## [7] "sa:haza" "za:haza" "sasa:za" "zasa:za" "sa:sa:za" "za:sa:za"
## [13] "saha:za" "zaha:za" "sa:ha:za" "za:ha:za" "sasaha" "zasaha"
## [19] "sa:saha" "za:saha" "sahaha" "zahaha" "sa:haha" "za:haha"
## [25] "sasa:ha" "zasa:ha" "sa:sa:ha" "za:sa:ha" "saha:ha" "zaha:ha"
## [31] "sa:ha:ha" "za:ha:ha"
The only extra bit that we need to do here is eliminate some words that have meanings in Serbian already
Fortunately there are only two of them
ToExclude <- c('papaka', 'pa:paka')
PlosiveWords <- setdiff(PlosiveWords, ToExclude)
And then a tiny bit of code just deleting all of the stored vectors and data frames that we no longer need
rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList, Chosen, Chosen1JC, Chosen1Num, Chosen2JC, Chosen2Num, Chosen3JC, Chosen3Num, Chosen4JC, Chosen4Num, ChosenSplit, Conv1Cons, Conv1Syll1, Conv1Syll2, Conv1Syll3, Conv1Words12, Conv2Cons, Conv2Syll1, Conv2Syll2, Conv2Syll3, Conv2Words12, SonorantCons, SonorantSyll1, SonorantSyll2, SonorantSyll3, SonorantWords12, filelist, FilesToDelete, FilesToKeep, PlosiveCons, PlosiveSyll1, PlosiveSyll2, PlosiveSyll3, PlosiveWords12, list, NewNames, newnames, oldnames, OriginalNames, ToExclude, Vowels)
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'chosen' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen1' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen2' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen3' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen4' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'BalanceList' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen1JC' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen1Num' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen2JC' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen2Num' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen3JC' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen3Num' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen4JC' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'Chosen4Num' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'ChosenSplit' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'filelist' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'FilesToDelete' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'FilesToKeep' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'list' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'NewNames' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'newnames' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'oldnames' not found
## Warning in rm(chosen, Chosen1, Chosen2, Chosen3, Chosen4, BalanceList,
## Chosen, : object 'OriginalNames' not found
Each participant uses 16 microbes for Training, 24 microbes total
This means that they need 8 “jagged” and 8 “curvy microbes” for training- 2 of each ‘subtype’ (Overall 12 jagged and 12 curvy, 3 of each subtype)
lister = 1:5
Chosen1 <- sample(lister, 3)
Chosen1 <- c(Chosen1, (Chosen1 +5))
Chosen2 <- sample(lister, 3)
Chosen2 <- c(Chosen2, (Chosen2 +5))
Chosen3 <- sample(lister, 3)
Chosen3 <- c(Chosen3, (Chosen3 +5))
Chosen4 <- sample(lister, 3)
Chosen4 <- c(Chosen4, (Chosen4 +5))
ChosenImages <- ImageStims[c(Chosen1, Chosen2+10, Chosen3+20, Chosen4+30),]
StarterImages <- ChosenImages[c(1,2,4,5,7,8,10,11,13,14,16,17,19,20,22,23),]
SecondaryImages <- ChosenImages[c(3,6,9,12,15,18,21,24),]
We now have all of the images chosen for a given participant
We just need to choose what words will be used for each participant NOTE- When I write this properly as a function call we will need to include a specification of the CONDITION in the function call- because what condition a participant is in determines what words are assigned to what images
As we are writing this basic version for Condition 4 (Systematic + Congruent) we need to select 12 Jagged Words and 12 Curvy Words
PlosiveSelected <- sample(PlosiveWords, 12)
SonorantSelected <- sample(SonorantWords, 12)
PlosiveStarter <- PlosiveSelected[1:8]
PlosiveSecondary <- PlosiveSelected[9:12]
SonorantStarter <- SonorantSelected[1:8]
SonorantSecondary <- SonorantSelected[9:12]
Now we need to pair our Words and our Images
First we
StarterJagged <- subset(StarterImages, Shape == "J" )
StarterCurved <- subset(StarterImages, Shape == "C" )
StarterJagged <- subset(as.data.frame(cbind(StarterJagged, PlosiveStarter)), select = c("NewName", "PlosiveStarter"))
StarterCurved <- subset(as.data.frame(cbind(StarterCurved, SonorantStarter)), select = c("NewName", "SonorantStarter"))
colnames(StarterJagged) <- c('Image', "Label")
colnames(StarterCurved) <- c('Image', "Label")
SecondaryJagged <- subset(SecondaryImages, Shape == "J")
SecondaryCurved <- subset(SecondaryImages, Shape == "C")
SecondaryJagged <- as.data.frame(cbind(SecondaryJagged$NewName, PlosiveSecondary))
SecondaryCurved <- as.data.frame(cbind(SecondaryCurved$NewName, SonorantSecondary))
colnames(SecondaryJagged) <- c('Image', "Label")
colnames(SecondaryCurved) <- c('Image', "Label")
StarterPairs <- rbind(StarterJagged, StarterCurved)
SecondaryPairs <- rbind(SecondaryJagged, SecondaryCurved)
rm(Chosen1J, ChosenImages, ImageStims, ImageStims1, ImageStims2, ImageStims3, ImageStims4, SecondarySonorant, SecondaryImages, SecondaryPlosive, StarterSonorant, StarterImages, StarterPlosive, Type1chosen, Type2chosen, Type3chosen, Type4chosen, Chosen1, Chosen2, Chosen3, Chosen4, SonorantSecondary, SonorantSelected, SonorantStarter, ImageSplit, PlosiveSecondary, PlosiveSelected, PlosiveStarter,lister, x, Conv1Words, Conv2Words, PlosiveWords, SonorantWords)
So now we have our lists of paired Labels and Images… that was a ton of work eh?
Now we can actually set up the trial structure
niiiiiiicee…
There are 9 Training Blocks
In each of the 9 training blocks participants see all 16 of the images (in Randomized Order)
During training they are asked whether they would approach or avoid the microbe. There are four canonical directions that the astrobiologist might approach a microbe from- the left, right, up, or down (and thus, “approaching” is a different response on each type of trial)
The position (and direction of approach) of the astromicrobiologist is counterbalanced - so on a given block each direction of approach is used 4 times
StimList <- rbind((StarterPairs[sample(nrow(StarterPairs)),]),(StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]), (StarterPairs[sample(nrow(StarterPairs)),]))
StimList$TrialNum <- 1:144
StimList$TrialType <- "Training"
StimList$Block <- rep(1:9, each=16)
StimList$BlockTrial <- rep(1:16, 9)
Condition <- 4 ## Comment this out or delete it once you functionalise this code
StimList$Condition <- Condition
library(tidyr)
StimList <- separate(data = StimList, col = Image, into = c('ImageSeed', 'ImageShape', "ImageCurviness", "ImageType"), sep = "-", remove = FALSE)
StimList$LabelType <- substring(StimList$Label, 1, 1)
library(plyr)
StimList$LabelType <- mapvalues(StimList$LabelType,
from = c('m', 'n', 'p', 't', 'f', 'v', 's', 'z'),
to = c('S', 'S', 'P', 'P', 'C1', 'C1', 'C2', 'C2'))
## The following `from` values were not present in `x`: f, v, s, z
Locations <- c('Left', 'Right', 'Up', 'Down')
Locations <- c(Locations, Locations, Locations, Locations)
StimList$Location <- c(sample(Locations), sample(Locations), sample(Locations), sample(Locations), sample(Locations), sample(Locations), sample(Locations), sample(Locations), sample(Locations))
StimList$Approach <- mapvalues(StimList$Location,
from = c('Left', 'Right', 'Up', 'Down'),
to = c(39, 37, 40, 38))
StimList$Retreat <- mapvalues(StimList$Location,
from = c('Left', 'Right', 'Up', 'Down'),
to = c(37, 39, 38, 40))
SubConditions <- c('J', 'C')
StimList$SubCondition <- sample(SubConditions, 1)
StimList$CorrectResponse <- ifelse(StimList$ImageShape == StimList$SubCondition, StimList$Approach, StimList$Retreat)
setwd('F:/Experiments/Collaborations/Stekic et al/Data/Stimlists/')
write.csv(StimList, "StimList-Sample.csv")
So, that’s everything that we need for a stimlist, and the stimlist has been saved as a “.csv”, which can be read in by jsPsych.