| Reference | Downloads | Github

Randomize trial order without repeating stimuli twice in a row

If this template helps then use it. If not then just delete and start from scratch.

OS : Win10
PsychoPy version : 3.0.5
Standard Standalone? (y/n) : yes

I am running a study where 4 stimuli are presented a number of times per block. Specifically, I have a .csv file with 24 rows, and there are 4 stimuli in one of the columns of the .csv file with each stimulus repeating 6 times. For each block, I need the rows to be randomly selected. However, I also need to make sure each stimulus is never repeated. As an example, the 4 stimuli are: lavender, lilac, lemon, pear. Each should be presented 6 times per block, and in a random order without any stimuli presented twice. For instance, if they see a lemon, the next stimulus must be random, but it cannot be a lemon again. I cannot figure out a code component I could put at the beginning of each block that would achieve this. Any help would be greatly appreciated. Thank you!

This kind of custom randomisation constraint can’t be implemented within Builder’s available options using a conditions file. What you need to do is insert a code component and use custom code to generate a new randomised conditions file (or list of conditions in memory) on each run.

A possible algorithm would be:

  • create a reference list ['lavender', 'lilac', 'lemon', 'pear']
  • copy it.
  • shuffle that copy. This is now the first 4 conditions, in order.
  • copy the reference list again.
  • extract the item from it that is the same as the last item of the first list.
  • randomly sample one of the three remaining items and append it to the first list.
  • put the extracted item back in the second list.
  • shuffle the second list.
  • extend the first list with the second list (which now contains 3 items). The result is now the first 8 conditions in order.
  • repeat the previous 6 steps 4 times.
1 Like

I don’t use Builder, but I have a piece of code (using numpy) at the start of an experiment that loops through my randomised list of stimuli to check for identical items in subsequent rows, and reshuffles the list (and checks again, and reshuffles if needed…) until there are none. This does introduce a short waiting time at the start, but never too long in my experience.

# make sure the same target doesn't appear on consecutive trials
doubletarget = False
listok = False

while listok == False:
    for i in range(len(practiselist)-1):
        if practiselist[i,stimTextCol] == practiselist[i+1,stimTextCol]:
            doubletarget = True
    if doubletarget == True:
        practiselist = np.random.permutation(practiselist)
        print("reshuffle practiselist...")
        doubletarget = False
        listok = True
1 Like

Yes, that’s the sort of non-deterministic, brute force approach I’ve usually used in the past, and is a good general solution for all sorts of constraints. For a long list, with different constraints, it might take hundreds or thousands of attempts to find a winner, but that won’t usually take more than a second or two.

In this case I realized that there is a deterministic algorithm that could solve the constraint in one go, but the structure of your code does provide a more general solution for other sorts of constraints too. And in this case, it is certainly simpler to implement as well.

Your proposed solution will (should?) take the exact same time to come up with a suitable stimulus list on every run, which I might need at some point in the future, so I’m saving it for future reference for myself. But I was too proud of my little code snippet not to show it off, and I hope it’s useful to someone with the same general problem.

1 Like