I am building a simulator for a task that has two conditions. On each trial, the condition is supposed to go back and forth between the two levels of nCond
and the respective index of the other variables. For example, trial 1 should have the stimulus "R", a pi value of .75, and a difficulty diff
that is "Easy." Trial two should have the stim
"L", pi of .65, and diff
of "Hard", the trial three should go back to mirror trial 1 with slightly different end RTs.
What is instead happening is every trial has a condition of 2, stimulus of "L", and the same pi/mean_a/a_s/etc. I'm sure it's likely a minor issue with the second loop concerning the mycond
index, but I can't quite figure out how to fix it.
Would greatly appreciate any help!
#Set a seed
set.seed(2024)
#Variable declaration-------------
nConds <- 2 #Number of conditions
stim <- c("R", "L") #Stimulus labels
pi <- c(.75, .65) #Probability of step (+1) for random walk; 1-pi will be the probability of stepping -1
diff <- c("Easy", "Hard") #Difficulty label for the condition
mean_a <- c(40, 40) #Mean upper bound for each condition
a_s <- c(0, 0) #Variability in upper bound for each condition
zp=c(.5, .5) #Multiplier of a for starting point for condition (Z = a*zp)
zp_s=c(0, 0) #Variability for starting point multiplier
Nsubs=1 #Number of subjects
Trials_per_cond=100 #Number of trials per condition
timeout=500 #Timeout parameter for the random walk
#Create an empty dataframe for storing responses
mydata=data.frame("Sub"=rep(1:1, each=100), "Trial"=1:100, "RESPONSE"=NA, "RT"=NA)
for (myperson in unique(Nsubs)){
for (mycond in 1:nConds){
condpi=pi[mycond]
cond_a=mean_a[mycond]
cond_a_s=a_s[mycond]
cond_zp=zp[mycond]
cond_zp_s=zp_s[mycond]
cond_stim=stim[mycond]
cond_diff=diff[mycond]
for (i in 1:Trials_per_cond){
mytrial=i
trial_a=rnorm(1, mean=cond_a, sd=cond_a_s)
trial_Z=rnorm(1, mean=trial_a*cond_zp, sd=cond_zp_s)
trial_Pi=rnorm(1, mean=condpi, sd=0)
#Begin setup for random walk
time=0
curpointer=trial_Z
#Conduct random walk
while (time < timeout){
time=time+1
curpointer=curpointer+sample(c(-1, 1), size=1, prob = c(1-trial_Pi, trial_Pi))
if (curpointer >= trial_a) {
myresponse="1"
break
}
else if (curpointer <= 0){
myresponse="0"
break
}
}
myRT=abs(time)
#Save the parameters to the respective trial in the dataframe
mydata[mydata$Sub==myperson & mydata$Trial==mytrial,"RESPONSE"]=myresponse
mydata[mydata$Sub==myperson & mydata$Trial==mytrial, "RT"]=myRT
mydata[mydata$Sub==myperson & mydata$Trial==mytrial, "Condition"]=mycond
mydata[mydata$Sub==myperson & mydata$Trial==mytrial, "Stimulus"]=cond_stim
}
}
}
Right now the end table looks something like this:
mydata
|sub|Trial|RESPONSE|RT |Condition|Stimulus|
|1 |1 | 1 |100 | 2 | L |
|1 |2 | 1 |130 | 2 | L |
|1 |3 | 1 |98 | 2 | L |
.....
|1 |98 | 1 |65 | 2 | L |
|1 |99 | 1 |120 | 2 | L |
|1 |100 | 1 |100 | 2 | L |
It should look like this:
mydata
|sub|Trial|RESPONSE|RT |Condition|Stimulus|
|1 |1 | 1 |102 | 1 | R |
|1 |2 | 1 |111 | 2 | L |
|1 |3 | 1 |65 | 1 | R |
.....
|1 |98 | 1 |98 | 1 | R |
|1 |99 | 1 |120 | 2 | L |
|1 |100 | 1 |100 | 1 | R |
Essentially, your innermost loop overwrites the row since both mycond
iterators share same Sub
and Trial
conditions. Consider adding Condition
as a present column in empty data frame and also in logical condition:
#Create an empty dataframe for storing responses
mydata = data.frame(
"Sub"=rep(1:1, each=100), "Trial"=1:100, "Condition"=rep(1:2, 50)
)
...
#Save the parameters to the respective trial in the dataframe
row_filter <- mydata$Sub==myperson & mydata$Trial==mytrial & mydata$Condition==mycond
mydata[row_filter, "RESPONSE"] = myresponse
mydata[row_filter, "RT"] = myRT
mydata[row_filter, "Stimulus"] = cond_stim
By the way, consider a more functional form of assigning values iteratively. Since you are running elementwise across rows, use mapply
and avoid nested for
loops:
run_walk <- function(mytrial, mycond) {
condpi=pi[mycond]
cond_a=mean_a[mycond]
cond_a_s=a_s[mycond]
cond_zp=zp[mycond]
cond_zp_s=zp_s[mycond]
cond_stim=stim[mycond]
cond_diff=diff[mycond]
trial_a=rnorm(1, mean=cond_a, sd=cond_a_s)
trial_Z=rnorm(1, mean=trial_a*cond_zp, sd=cond_zp_s)
trial_Pi=rnorm(1, mean=condpi, sd=0)
#Begin setup for random walk
time=0
curpointer=trial_Z
#Conduct random walk
while (time < timeout){
time=time+1
curpointer=curpointer+sample(c(-1, 1), size=1, prob = c(1-trial_Pi, trial_Pi))
if (curpointer >= trial_a) {
myresponse="1"
break
}
else if (curpointer <= 0){
myresponse="0"
break
}
}
return(
c(RESPONSE=myresponse, RT=abs(time), STIMULIS=cond_stim)
)
}
# CREATE EMPTY DATA FRAME
mydata2 <- data.frame(
Sub = rep(1:1, each=100), Trial = 1:100, Condition = rep(1:2, 50)
)
# ASSIGN TRANSPOSED MATRIX VALUES TO COLUMNS
mydata2[,c("RESPONSE", "RT", "STIMULIS")] <- with(
mydata2,
t(mapply(run_walk, Trial, Condition))
)
# CONVERT SOME COLUMNS TO INTEGER FROM FULL CHARACTER MATRIX
mydata2 <- transform(
mydata2,
RESPONSE = as.integer(RESPONSE),
RT = as.integer(RT)
)