psychopy.org | Reference | Downloads | Github

Randomly selecting and grouping rows from a conditions file


#1

Apologies if this issue has been posted before. I have a conditions file called cond.xlsx with a single column and 6 rows, each containing a different item of fruit.

Capture

I would like to write a code component at the beginning of my experiment which randomly sorts the rows into three conditions, each containing 2 rows. Ideally this would create a ‘temporary’ dict object (apologies if I’m using incorrect terminology) that would allow me to call rows from each condition in subsequent loops in the experiment.

Here is my code:

conditions = data.importConditions(u’cond.xlsx’)
shuffle(conditions)
cond_A = conditions[0:2]
cond_B = conditions[3:4]
cond_C = conditions[5:6]

I would then call specific conditions in subsequent loops:

Capture2

Ultimately I would like a way to record which items of fruit were assigned to each condition at the end of the experiment. However, when I try to run the experiment as-is, I get the following error

Capture3
################

If anyone can suggest a fix (and/or a way to save a record of which rows/items of fruit were assigned to each condition) I would be very grateful for the advice. Thanks in advance!


#2

The selected rows field has to contain integers (ie the indices of the rows, not the content of the rows themselves).

You can achieve what you want without any code.

  • Put some fixed ranges in each of your loops (eg [0, 1] followed by [2, 3], etc).
  • Set each loop to be random but supply a common seed value so that the randomisation is constant across each loop.
  • I guess you want the randomisation to vary across subjects however, so enter a new seed value on each session into the information dialog at the start of the experiment, and refer to that variable from the expInfo dialog in each seed field.

#3

Hi Michael

Thanks for the reply! I’m having trouble calling the expInfo as you suggested. I entered a new row in ‘Experiment settings’:

Capture

and then entered expInfo.setSeed in the seed field for each loop. This causes the following error:

AttributeError: 'dict' object has no attribute 'setSeed'

I also tried automating the process by instead creating a code component with
setSeed = random.randint(0,1000) # should select a random seed value between 0 and 1000

This runs fine (and seems to be selecting random rows, as intended), but after running the experiment a few times I realized it’s pulling the SAME selection of rows each time, so random.randint must be assigning the same value to setSeed each time…?


#4

The dot notation gives you access to the methods of the dictionary class, things like .keys(), copy(), etc. You look up individual values in Python dictionaries like this:

expInfo['setSeed']

See https://www.tutorialspoint.com/python/python_dictionary.htm


#5

Ah! That makes sense. I tried using expInfo[‘setSeed’] and got the following error:

File “mtrand.pyx”, line 684, in mtrand.RandomState.seed (numpy\random\mtrand\mtrand.c:13996)
TypeError: Cannot cast array from dtype(’<U2’) to dtype(‘int64’) according to the rule ‘safe’

My understanding is that the value from expInfo[‘setSeed’] should be converted to float, which I tried to do with a code component:

randValue = expInfo[‘setSeed’]
randSeed = map(float, randValue)

But no luck! Can you suggest a work around? Again, thanks in advance for the help :slight_smile:


#6

Try:

eval(expInfo['setSeed'])

#7

Hi Michael,

Thanks for the reply! The suggestion worked (in that no errors occurred), however I found that this pulled exactly the same rows for each condition on every run, regardless of what seed value I provided :frowning:

SO I figured out a workaround. I did away with the seed values, and created a shuffled array of values corresponding to rows in my conditions file:

import random
array = [0,1,2,3,4,5]
shuffle(array)

I then assigned a range of indices in the (now shuffled) array to keys in a dictionary:

a = array[0:2]
b = array[4:6]
dict = {'cond_A':a,'cond_B':b}

and called a random key for each loop (note that in the builder I set the rows field of my two loops to $loop1 and $loop2)

x = random.choice(dict.keys())
loop1 = []
loop2 = []

loop1 = dict.get(x) 

if loop1 == dict.get('cond_A'):
    loop2 = dict.get('cond_B')
elif loop1 == dict.get('cond_B'):
    loop2 = dict.get('cond_A')

note that this can be tweaked to include a third condition (in this case, cond_C) using nested if-else function:

if loop1 == dict.get('cond_A'):
    if random.random()>0.5:
        loop2 = dict.get('cond_B')
    else:
        loop2 = dict.get('cond_C')
elif loop1 == dict.get('cond_B'):
    if random.random()>0.5:
        loop2 = dict.get('cond_A')
    else:
        loop2 = dict.get('cond_C')
elif loop1 == dict.get('cond_C'):
    if random.random()>0.5:
        loop2 = dict.get('cond_A')
    else:
        loop2 = dict.get('cond_B')

I’m happy to say that this works like a dream, however I’m now stuck on the final component of the experiment. I’d like to add a routine which presents two items of fruit, side-by-side, on each trial. Critically (and herein lies the problem), each item of fruit needs to be paired with another from the same randomly assigned condition. So, if ‘apple’ was in cond_A, it needs to be paired with something else from cond_A, and so on.

I’ve created a loop called testTrials, and a routine with two text components, fruit1 and fruit2 (each with a different x,y position). fruit1 calls $fruit from my original conditions file, and I’ve entered $fruit2_text in the text field of fruit2. I imagine a code component that looks something like this:

fruit2_text = []

for i in dict.keys():
    if testTrials.thisIndex == i in loop1:
        fruit2_text = i in loop1
    elif testTrials.thisIndex == i in loop2:
        fruit2_text = i in loop2

But beyond this I’m not sure what to do. The problem is complicated by the fact that it’s rather unusual to call items from different rows within the same trial (and I would like to avoid a nested loop because this would introduce a degree of sequential presentation into my otherwise randomized loop). If anyone has any suggestions as to how to proceed I would be very grateful :slight_smile: