Randomly selecting a subset of 5 excel rows from groups of 10 rows on each trial

I am making an experiment in Builder with 5 blocks (Mac/standalone/v1.90.3). My 4 experimental adapt blocks work fine in their nested loops which randomly present each block using a block order excel file in the outer loops condition filed and $variable in the inner loops.

My control block must always be presented first, so has its own loop setup (perhaps this is not the most elegant way to do this). My question is about how I want to select rows from my control excel file in a particular way on each trial:

My .xlsx file has 40 rows each linking to a .jpg:
The first 10 rows are part of group A
Next 10 are part of B
Next 10 group C
Last 10 are D

How do I randomly select 5 rows from each group on each trial? The desired outcome is that I have 20 randomly selected (in a constrained way) .jpg files I can use as the ‘movie’ for each trial in the control block.

I don’t understand how I could make selected rows field do this.

I have been trying to work out how to import random and then shuffle conditions, but can’t see where to add the code snippets and/or which code tab.

I’ve not found this solution here

or here

or on other threads.

Can anyone help please?

4 Likes

Hi @kirsten, you’re right, you can’t really make this work just by using the loop dialog options. The randomising and row selection work across the entire file, which is incompatible with having separate blocks within that file.

You need to put each block in its own .xlsx or .csv file. We then control the order of selection of those blocks with code. Insert a code component and put something like this in the “Begin Experiment” tab:

control_blocks = ['A.csv', 'B.csv', 'C.csv', 'D.csv']
shuffle(control_blocks) # randomise order

In the inner loop dialog for your control condition, put this in the conditions file field:

$control_blocks.pop()

and set the “selected rows” field to 0:5 to get just five of the rows (set the loop type to “random”).

Then surround that with an outer loop that isn’t connected to a conditions file but simply set to have an nReps of 4, so that the control condition runs four times (for a total of 20 trials).

Check your data output, I’m not sure if the conditions file name will be saved automatically for you (if that matters).

1 Like

Dear Michael,
thank you so much for this very helpful response. I have done as you suggested, but have hit a wall with a syntax error for the ‘selected rows’ field (see screenshot). If I use other notation like ‘0-1’ or ‘1,2,3’ or ‘{0:5}’ there is no problem, but of course these don’t do what I want. Reading other posts about selected row errors makes me think that I must have another error in my code - like perhaps the ordering of my components is wrong? But I haven’t been able to loose the error despite trying different orders.
I have attached the files I have been working on, if that helps. The image folder has only 8 pictures.
While I’m here I would also like to mention that I have gained a lot from your PsychoPy book. It’s really nicely written.
Thanks,
Kirsten


Adapt_draft7aTest.psyexp (11.7 KB)
BlockSalty.xlsx (8.7 KB)
BlockSweet.xlsx (8.7 KB)

1 Like

It seems to me that adding an expression in the “selected rows” field can be a bit fragile. Once the loop dialog box gets convinced it contains a syntax error, it is hard to convince it otherwise. Perhaps it might be easiest to delete the loop and try re-inserting it. I managed to type 0:5 in your experiment without it raising an error, for example.

Thank you Michael. Thank you so much. After fulling closing and reopening Psychopy and carefully entering 0:5 it now runs with no errors. However, it is the case that the same images are always being presented. Not a random selection of the 0:5 (or 0:1) for example.
I’ve set both loops to full random. I’m now wondering about the random seed?

…And FYI, yes, you’re right that the data output does not save the conditions file name, but that is no problem for me.

Many thanks,
Kirsten

“Full random” only applies when there is more than one repetition of a conditions file. Just “random” is sufficient here (but won’t actually alter anything here).

You shouldn’t be specifying a seed (that makes the random order constant across different runs).

If you haven’t specified a seed, then I’m not sure how you can be getting the same random selection on different runs. Are the images constant, but the order changes, or are both the order and the images constant from one run to the next?

If you just enter 0 in the selected rows field, do you always get the same image, and if so, is it the first one in your conditions file?

Okay yes.
The images are constant, but the order changes.
Yes, when set to selected rows in 0, it is always the same image, and it is the first one in the conditions file.

So the presentation might be one run
cake, cucumber
and the cucumber, cake
on the next run.
Where cake is first row of conditions file A
and cucumber is first row of conditions file B.

Sorry, I always get this wrong: the selected rows are extracted first, prior to the randomisation being applied, which is why you are getting a variable order but from a constant selection of rows. So instead of specifying rows 0:5, which will always be the first ones, we need to provide a list of 5 random, potentially non-contiguous indices from across the whole span of row numbers. So if there are 10 rows in your conditions file, you could try an expression like this in the selected rows field:

choice(10, size=5, replace=False)

In the “begin experiment” tab, you would first need to import that function:

from numpy.random import choice
4 Likes

Thank YOU! This works perfectly. I just popped a $ in front of `$choice(10, size=5, replace=False).
I have attached the working exp for anyone else who is interested in this thread.
RandomSelectSubset.psyexp (7.2 KB)
BlockSalty.xlsx (8.6 KB)
BlockSweet.xlsx (8.6 KB)

YAY… it looks like we can start testing those participants that are booked for tomorrow! Great news! Thanks again,
Kirsten
`

5 Likes

Thank you @Michael for this great explanation of the issue above. If I can ask one more think on top of the rest: Now we are popping a “csv file” at the beginning of each routine which logically results in an empty list at the end. So after the iterations the “control_blocks” is empty as we have popped out the choices. How can I restore this list?

I have tried adding the control_blocks = [‘mycsv1.csv’, ‘mycsv2.csv’, ‘mycsv3.csv’, ‘mycsv4.csv’] at the start of the routine but then it doesn’t run (which actually makes sense) .

The reason that I want to restore it is because on the above example if we set the nReps to 4 then it will go 4 times through mycsv1, then continue 4 times through mycsv2 and so on. What I want is go once into mycsv1, then continue to mycsv2 and so on… but iterate over this 4 times.
If I add an outer loop of doing this with 4 times it stops after the first iteration. I speculate this is because the control_blocks list is empty now.

Thanks

I’m not sure I entirely understand what is going on here, but you don’t need to use .pop() to get an item from the list. You could just get an item from the list by an index, which would leave the list intact. e.g.

$operation_blocks[some_loop.thisN]

would give you the zeroth item from the list on the first iteration of the enclosing loop (use whatever loop makes sense, Guess here it is the next enclosing loop, called trials? (it does make sense to give loops descriptive names so their function is clear)).

Presumably you’ll want to shuffle that list at the start of each block, so insert a code component and put something like this in the “begin routine” tab:

if whatever_loop_name.thisN == 0:
    shuffle(operation_blocks)
2 Likes