Here you will find a Python function for randomization with constrains. This was written, specifically, for a psychological experiment (a shifting/task-switching task) I was planning to conduct. For this experiment, I needed a list of stimuli names that were quasi-randomized.  Fifty percent of the items in the list are followed by a stimulus in the same colour and the remaining 50 % are followed by a stimulus in a different colour.

Python script


from random import shuffle
from collections import Counter

liststim = []
colors, firstfigures = ['Black', 'Blue'], ['Rect', 'Triangle', 'X', 'Circle']
secondfigures = firstfigures
for col in colors:
    for figure in firstfigures:
        for figure2 in secondfigures:
            liststim.append(col + '-' + figure + '_' + figure2)

def randShift(listostim, ntrials):
    '''
    Will randomize 50 % of shifting trials
    based on that each filename (of the images) starts with Black or Blue-.
    
    listostim is a list of trials
    ntrials is an integer indicating number of trials
    '''
    nEachstim = ntrials/len(liststim) #Number of each stim is going to be even
    stimList = listostim 
    trialTypes = [] 
    stims = []
    countOfStim = dict((el,0) for el in stimList)
    count = {'ns':0,'s':0}
    for i in range(ntrials):
        shuffle(stimList)
        for idx in range(len(stimList)):
            if not stims:
                countOfStim[stimList[idx]] +=1
                stims.append(stimList[idx])
                count['ns'] +=1
                trialTypes.append("No-Shifting")
            elif stims:
                if count['s'] <= ntrials/2:
                    if countOfStim[stimList[idx]] <= nEachstim-1: if stimList[idx][:5] != stims[i-1][:5]: count['s'] +=1 countOfStim[stimList[idx]] +=1 stims.append(stimList[idx]) trialTypes.append("Shifting") else: count['ns'] +=1 countOfStim[stimList[idx]] +=1 stims.append(stimList[idx]) trialTypes.append("No-Shifting") elif count['s'] > ntrials/2:
                    if countOfStim[stimList[idx]] <= nEachstim-1: 
                        if stimList[idx][:5] == stims[i-1][:5]:
                            count['ns'] +=1
                            countOfStim[stimList[idx]] +=1
                            stims.append(stimList[idx])
                            trialTypes.append("No-Shifting")
    #Frequency of the trialtypes
    freq = Counter(trialTypes).values()

The last code snippet, below, crucial for the script to be fully functional since. That is, sometimes the randomization will fail and, therefore, the code below first checks that the wanted output has been generated. That is, it is 50% items that are of a color and then followed by a different color? An additional check is also made to make sure that there are as many items that were  required (i.e-, number of trials; ntrials). The last line of code call the function, with a list, and number of trials.


    if freq[0] == freq[1] and sum(freq) == ntrials:
        return stims
    #We need to run again if the constrains we need is not satisfied
    elif freq[0] != ntrials/2 and freq[1] !=ntrials/2 or sum(freq) !=ntrials:
        return randShift(stimList, ntrials)

randomized = randShift(liststim, 96)

The script solved my problem of quazi-randomization and it is pretty quick. However, if you know a better method I would love to see it.

Link to the full script on pastebin. If you are interesting in another randomization script using PsychoPy click here.

Share via
Copy link
Powered by Social Snap