psychopy.org | Reference | Downloads | Github

Equal distribution of trials among conditions

Hi,

I have 5 conditions regarding the congruency between 3 different types of stimuli. When I run the experiment, the number of trials were not distributed to the conditions equally. Is there a way to do it?

The way I’ve most recently approached this issue is to set up a shuffled list of conditions for each type of stimulus and .pop() one from the appropriate list for each trial.

Hi There,

An easier way to do this might be to set this in the conditions trial spreadsheet you feed in - for example if I have 10 trials and I was 5 congruent and 5 incongruent - I would simply ensure that 5 rows in the conditions file corresponded to congruent and 5 corresponded to incongruent. Is there a reason that you prefer to manipulate this through code rather than from the spreadsheet?

Thanks!
Becca

1 Like

Try

conditionChoice1 = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
shuffle(conditionChoice1)
conditionChoice2 = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
shuffle(conditionChoice2)
conditionChoice3 = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
shuffle(conditionChoice3)

if stimType == 1:
     thisCondition = conditionChoice1.pop()
elif stimType == 2:
     thisCondition = conditionChoice2.pop()
elif stimType == 3:
     thisCondition = conditionChoice3.pop()

where stimType is a column in the spreadsheet

1 Like

I suspect that you are re initialising the list every time. The setup and shuffle should be in Begin Experiment.

Please could you show the code you’re trying and confirm the total number of each cond_number

That’s the error I expected you to get.

When you create the conditionChoice lists in Begin Experiment you need to make sure they have enough in them for all of your trials. If you have 127 trials divided by 3 values for cond then that’s about 42 values for each. You’ll need to go slightly over if you don’t have a multiple of 5.

However, in your code I note that you have cond = 4 and 5 as well. If cond is a column in your spreadsheet then you will have problems online if you try to alter it in your code.

Does cond 4/5 need a value for thisCondition or not?

It might be worth trying to call cond and thisCondition something more different. I’m confused about what two variables you are trying to randomise here.

If this is true then you need more than 30 items in conditionChoice2.

Yes I do not understand why this happens.

Can it be due to the fact that probablity of having condition 2 is somehow more than the others?

How many times does condition 2 occurs in your 127 trials? If you can’t work that out, then you should step back and think about how your conditions are defined.

1 Like

This is a fun little exercise in probability. As I understand it, you have three categories of stimuli: images, words, and square. Congruency is defined by the matching index values between the three categories of stimuli. If this is right, then here’s one approach from my end:

1. Generate and group into conditions all possible triplet combinations
Just as was noted in this post’s discussion, there’s an uneven amount of triplets per condition when you group together the triplets. To prevent an uneven distribution, you should explicitly sample from each condition group, as sampling independently from each stimulus category (i.e., choose a random image, random word, and random square out of options 1-6) will likely return a triplet that falls under the all-incongruent condition. This is because, out of 216 possible combinations (because you have [6 options] to the power of [3 chosen]), 120 out of 216 triplets are all-incongruent.

So, how can we do this? Using two key elements:

  • The handy itertools package’s product function
  • Numpy's unique function, which you can use to analyze the occurrence of elements in the triplet (or any other array)
from itertools import product
import numpy as np

# set up the options (1-6 images or words or imagery)
dataset = ['1', '2', '3', '4', '5', '6']

# initialize arrays to hold triplets per condition
cond1 = [] # all congruent
cond2 = [] # all incongruent
cond3 = [] # first two congruent (e.g., 1-1-2)
cond4 = [] # last two congruent  (e.g., 1-2-2)
cond5 = [] # first and third congruent (e.g., 1-2-1)

# product(dataset, dataset, dataset) returns all triplets for vals 1-6
for triplet in product(dataset, dataset, dataset): 
    vals, inv = np.unique(triplet, return_inverse=True) 
    # vals = unique values found in the triplet, so 112 -> [1, 2]
    # inv = indices to reconstruct original array - useful for us to group
    
    if len(vals) == 1:
        # if there's only 1 unique value, it's congruent
        cond1.append(triplet)
    elif len(vals) == 3:
        # if there are 3 unique values, it's completely incongruent
        cond2.append(triplet)
    elif len(vals) == 2: # if there are two unique values... 
        if all(inv == [0, 0, 1]) or all(inv == [1, 1, 0]): # and repeated value starts at position 0 (XXY)
            cond3.append(triplet)
        elif all(inv == [0, 1, 1]) or all(inv == [1, 0, 0]): # and repeated value starts at position 1 (XYY)
            cond4.append(triplet)
        else: # repeated values at 1st and 3rd position
            cond5.append(triplet)

I encourage you to run this segment of code in Python, then print some variables to make sense of it:

  • print(cond1) and swap cond1 for other variables to inspect the triplets and make sure it’s what you expect
  • print([len(cond1), len(cond2), len(cond3), len(cond4), len(cond5)]) will return an array with how many triplets are in each category. Use this to understand why your previous approach wasn’t resulting in an even distribution.

2. Creating an even distribution of conditions
Now, you can come up with a way to generate an array that will dictate which condition the triplet presented comes from. You’ll need to figure out a way to:

  • Generate an array that has 125 elements with numbers 1-5 each appearing 25 times representing an even distribution of conditions: [1, ..., 1, 2, ..., 2, 3, ...]
  • Shuffle it: [1, 5, 4, 2, 2, 3, 5, ...]
  • Use the array to choose which condition group (i.e., cond1, cond2, etc.) to randomly sample from: ['444', '626', '311', '352', '512', ...]
  • Map each value onto the stimuli: [(image4, word4, square4), (image6, word2, square6), ...]

Hope that helps!

1 Like

Thank you so much for your effort :hugs:
I guess it will take a while for me to understand this with my poor coding knowledge.

It should be possible to set up the spreadsheet with balanced numbers of your different conditions rather than using a fully coded solution.

Since every word, image, imagery is randomly selected among 6 options it is not possible to define a color for a possible combination. The combination is demonstrated only after a loop iteration (thisWord_color).

I do not know if there is a way to integrate possible combinations (attached) into the study excel sheet.

colorperm.xlsx (20.6 KB)

It looks to me that you have 5 conditions

What I would do is have a list of your six colours and shuffle before each trial.

allincong = colour[0], colour[1], colour[2]
allcong = colour[0], colour[0], colour[0]
imagewordcong = colour[0], colour[0], colour[1]
imageimagerycong = colour[0], colour[1], colour[0]
wordimagerycong = colour[0], colour[1], colour[1]

Unless you care about the specific colours, they just need to be random.

is there a way to assign these colour[…] variables to the images or words that is gonna be presented?

imageCol = colour[0]
wordCol = colour[1]
imageryCol = colour[2]

Have a look at my crib sheet for how to set up colours as variables.

1 Like

Yes, I just showed the principle, not all the variations. Please show the code you’ve tried.

You need if statements.

Try a conditions file with just one column called condType and then:

if condType == 'allincong':
     thisImage_color = colour[0]
     thisWod_color = colour[1]
     thisImagery_color = colour[2]
elif condType == 'allcong'
     thisImage_color = colour[0]
     thisWod_color = colour[0]
     thisImagery_color = colour[0]
# You will need to add the rest yourself

This didnt work either. Probably because there is no list called thisimage_color. Etc but the images are read from thisImage list. The color is randomly selected. Eventhough your suggestion works it only labels the existing conditions