psychopy.org | Reference | Downloads | Github

Counterbalance across multiple factors

Hi,

I am using builder to create my experiment which will be ran online. I am a bit new to python and don’t know much about coding. I am trying to counterbalance between 4 factors each with 2 levels which would lead to a total of 16 different combinations. I know that I can counterbalance this manually by setting up 16 different files and four different loops in order to do this. However, I am wondering if there may be a more convenient way to do this. Thank you in advance for your help!

Would you like to do so online or offline?

I intend to run the experiment online. I currently am creating an offline version of it in builder and will transform it into an online version.

Check. And these factors, what kind of design do they result in? I.e., what’s exactly the difference between the 16 versions of your experiment?

Hey,

Here is a script that might be useful to get started. I use this to generate conditions files automatically and save that manual work!

2 Likes

Thank you so much for your help!

Basically, I am trying to have my participants solve many maths problems. They will solve it in either blocked format or interleaved format. The factors I am trying to counterbalance are: condition(blocked vs. interleaved); number type(present fraction first vs. decimal first); operation(solve addition problem first vs. multiplication first); problem difficulty (hard first vs. easy first). Thank you for your help!

I see @Becca made a nice suggestion. Would that solve your problem?

Sorry for my delayed response. I suppose Becca gave me a good starting point, but it is a bit different from what I intend to do.
Basically, I have 8 different lists of stimuli containing 9 items in each. There are 16 different orders for me to arrange the 8 lists. I am hoping to retrieve each element from the list randomly.
As previously mentioned, I have two conditions: blocked or interleaved. In the interleaved condition, I want to have elements from different lists presenting consecutively, I found it difficult to implement without coding.
One way to do it is to set up 16 different conditions, but it is not as satisfying because then each condition only contains one fixed random order.
Do you have any thought on how I can do this? Thank you very much for your help!

I’ll go figure out if I can write a little example experiment that demonstrates the structure you need. But first, more questions :slight_smile:

  1. You write: “retrieve each element from the list (of 16 orders) randomly”. That’s between-subjects right? If I got this right, might be tricky to randomize, but is counterbalancing an option two?
  2. You’ve got two conditions (blocked or interleaved). Each of these conditions combines with each of the 16 orders, making 32 combinations?
1 Like

Thank you so much for your help!
1.Yes, It is between-subject. I am trying to counterbalance 4 factors here, which leads to 16 different ordering of 8 lists. In order words, I have 16 different conditions participants can be assigned to. I suppose I could instead just set up 16 different conditions files but it would be less ideal than if I am able to set up the experiment such that for each participant in the same condition, they may solve the problems in different orders. I am not sure if I explained it properly, please let me know if it is confusing.
2. I have two conditions and 8 different orders within each condition, making 16 different combinations. Below is a graph of the 8 possible orders within each condition. I hope it makes sense. Within each unique number type x number feature x operation combination, there are 9 different problems. I am hoping that within each order, when each time a list is call upon, a problem is randomly selected.

Thanks, that’s very clear! Got one more question before I start fidgeting with code. It might be that the 8 orders within a condition are easily put into a single experiment, but the 2 conditions wouldn’t. If it would result in 2 experiments, one per conditions, would that work out for you?

1 Like

Thank you so much for your help! On second thought, yes I suppose I can make it work that way!

OK, I’ve got something in mind, but it’s a different way of running loops that you’re used to:

  1. You’d need to construct a conditions array via programming code, based on the different orders you’d like to have.
  2. When you loop over it, you won’t be able to set stimulus parameters via $someparameter. Instead, it all has to be done via code.

If that’s OK, this is the approach. We use this experiment as a template: Thomas Pronk / demo_dynamic_loops · GitLab

Note that in this template, the second loop trials_2 doesn’t loop over a conditions file. Instead it sets up the stimulus_text using an array called stimuli. This array is constructed earlier in the experiment (in the trials loop). In your case, you can generate different values for stimuli to meet your design. Since the design is rather complicated, I’d recommend doing that completely via code component.

Below is a code snippet that could get you started; Basically we throw a coin; based on head/tails you’ll have decimal or fraction first. Then another coin for addition vs multiplication. The third factor isn’t demonstrated, but it’s just an extension of the same idea.
Same principle you can use for addition/multiplication, equal/unequal denominator.

// Stimuli per cell
decimal_addition = ['da1', 'da2', 'da3'];
decimal_multiplication = ['dm1', 'dm2', 'dm3'];
fraction_addition = ['fa1', 'fa2', 'fa3'];
fraction_multiplication = ['fm1', 'fm2', 'fm3'];

if (Math.random() < 0.5) {
  // decimal first
  if (Math.random() < 0.5) {
    // addition first
    stimuli = decimal_addition.concat(decimal_multiplication).concat(fraction_addition).concat(fraction_multiplication);
  } else {
    // multiplication first
    stimuli = decimal_multiplication.concat(decimal_addition).concat(fraction_multiplication).concat(fraction_addition);
  }
} else {
  if (Math.random() < 0.5) {
    // addition first
    stimuli = fraction_addition.concat(fraction_multiplication).concat(decimal_addition).concat(decimal_multiplication);
  } else {
    // multiplication first
    stimuli = fraction_multiplication.concat(fraction_addition).concat(decimal_multiplication).concat(decimal_addition);
  }
}
// Print to the terminal
console.log(stimuli);

Two final notes:

  1. However you turned, it will be a rather complicated algorithm, so test carefully
  2. You can easily try out the snipped above in the browser console. See this example: Thomas Pronk / tutorial_js_expose_psychojs · GitLab
1 Like

Thank you so much for your help! It looks amazing.

1 Like