psuedo-random order

260 views
Skip to first unread message

Nora

unread,
May 5, 2020, 7:43:28 PM5/5/20
to ibexexperiments
Hello!

I'm creating a self-paced experiment where I have a list of experimental items and fillers; I don't have a latin square design, so participants will see the entire list of items and fillers for the experiment. 
Ideally, I'd like to pseudo-randomize them in such a way that items and fillers will be randomized and shuffled, but no more than 3 items or 3 fillers can be presented in a row. 

I first used rshuffle(items, fillers), but this ended up giving me an even alternation of item, filler, item, filler, item, filler etc. I'd like the order to be more uneven.

I then tried with randomize(anyOf(items, fillers)), but this resulted in a random order that was too random, where I might get for example 10 fillers in a row.

Ideally the order would be more random than the first option (allowing up to 3 fillers or items in a row) but not as random as the second option.

Is there any way to implement this?

Thank you very much!

Jeremy Zehr

unread,
May 6, 2020, 11:06:41 AM5/6/20
to ibexexperiments
Hello Nora,

You can use this to achieve what you want (place this at the top of your script, or in a separate js file under js_includes):

function RandomizeNoMoreThan(predicate,n) {
   
this.args = [predicate];
   
this.run = function(arrays) {
        let moreThanN
= true;
        let order
;
       
while (moreThanN){
            order
= randomize(predicate).run(arrays);
            moreThanN
= false;
            let previousType
= "";
            let current_n
= 0;
           
for (let i = 0; i < order.length; i++){
                let currentType
= order[i][0].type;
               
if (currentType != previousType)
                    previousType
= currentType;
               
else{
                    current_n
++;
                   
if (current_n > n){
                        moreThanN
= true;
                       
break;
                   
}
               
}
           
}
       
}
       
return order;
   
};
}          
function randomizeNoMoreThan(predicate, n) {
   
return new RandomizeNoMoreThan(predicate,n);
}


Then you use it like this: randomizeNoMoreThan(anyOf(items, fillers),3)

Be very careful with it though, as it will freeze in an infinite loop if you don't have enough items with each label to consistently break series of N items sharing the same label. For example, if you have 12 test items and only 3 filler items, there is no way of avoiding at least one series of more-than-three test items (unless duplicating some filler items or subsetting the test items) and your experiment would end up crashing.

Jeremy

Jeremy Zehr

unread,
May 6, 2020, 11:11:52 AM5/6/20
to ibexexperiments
Oops, there was a problem with the code I posted, here is a fixed version:

function RandomizeNoMoreThan(predicate,n) {
   
this.args = [predicate];
   
this.run = function(arrays) {
        let moreThanN
= true;
        let order
;
       
while (moreThanN){
            order
= randomize(predicate).run(arrays);
            moreThanN
= false;
            let previousType
= "";
            let current_n
= 0;
           
for (let i = 0; i < order.length; i++){
                let currentType
= order[i][0].type;

               
if (currentType != previousType){
                    current_n
= 1;

Nora

unread,
May 6, 2020, 1:47:40 PM5/6/20
to ibexexperiments
Hi Jeremy,

Thank you, this is extremely helpful!
I just tried it and it works except for one aspect: my fillers all have the same label (just "filler"), but my items actually have different labels denoting different conditions (with 8 items per condition). All the item labels start with "FP_" so I've been using: randomizeNoMoreThan(anyOf(startsWith("FP_"), startsWith("filler")),3)

So right now the function prevents more than 3 fillers from being presented in a row, and more of 3 items with the same label from being presented in a row, but it allows more items with different labels to be presented in a row. Is there a way the function could prevent any item label (everything that starts with "FP_") from being presented more than 3 times in a row?

If this is too complicated I can just use the current version of the function! Thank you so much for your help! 

Jeremy Zehr

unread,
May 6, 2020, 4:46:37 PM5/6/20
to ibexexperiments
You could hardcode your specific needs in the function directly, by replacing let currentType = order[i][0].type; with let currentType = order[i][0].type.replace(/_.+$/,'');

Jeremy

Eleonora Beier

unread,
May 7, 2020, 3:00:30 PM5/7/20
to ibexexp...@googlegroups.com
Thanks so much, this works perfectly!



--
You received this message because you are subscribed to a topic in the Google Groups "ibexexperiments" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/ibexexperiments/1987FoZKo6k/unsubscribe.
To unsubscribe from this group and all its topics, send an email to ibexexperimen...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ibexexperiments/c84655e7-31d6-4ea1-874b-68a0b46ee689%40googlegroups.com.

Mala-in Kanyarat

unread,
May 10, 2020, 4:38:19 PM5/10/20
to ibexexperiments
Hello. Thank you for sharing the code. My experimental design is the exact same as Nora's. However, I tried it with your fixed code but it did not work. My experiment has 3 conditions for real items and 2 filler types. Could you please have a look at my scripts? I have no idea what the problem was.

function RandomizeNoMoreThan(anyOf("cond1", "cond2", "cond3", "filler1", "filler2"),3) {
    this.args = [predicate];
    this.run = function(arrays) {
        let moreThanN = true;
        let order;
        while (moreThanN){
            order = randomize(predicate).run(arrays);
            moreThanN = false;
            let previousType = "";
            let current_n = 0;
            for (let i = 0; i < order.length; i++){
                let currentType = order[i][0].type;

                if (currentType != previousType){
                    current_n = 1;
                    previousType = currentType;
                }
                else{
                    current_n++;
                    if (current_n > n){
                        moreThanN = true;
                        break;
                    }
                }
            }
        }
        return order;
    };
}           
function randomizeNoMoreThan(anyOf("cond1", "cond2", "cond3", "filler1", "filler2"),3) {
    return new RandomizeNoMoreThan(anyOf("cond1", "cond2", "cond3", "filler1", "filler2"),3);
}

var shuffleSequence = seq("intro", "instructions", "instructions2", "instructions3", 
                    sepWith("sep","practice"), "endPrac", "setcounter",
                    sepWith("sep", randomize(rshuffle("cond1", "cond2", "cond3","filler1","filler2"))),
                    "send_results", "end");

Jeremy Zehr

unread,
May 10, 2020, 4:54:25 PM5/10/20
to ibexexperiments
You're not supposed to directly edit the code I shared (but see note below); rather you should reference the randomizeNoMoreThan function as part of your shuffleSequence declaration, the same way you normally use randomize, eg.

var shuffleSequence = seq("intro", "instructions", "instructions2", "instructions3",
                    sepWith
("sep","practice"), "endPrac", "setcounter",

                    sepWith
("sep", randomizeNoMoreThan(anyOf("cond1", "cond2", "cond3","filler1","filler2"),3)),
                   
"send_results", "end");

If you want to prevent 3 "cond"s or three "filler"s from forming a sequence though, that's a situation where you'll want to edit the code as I described earlier for Nora's case---in your case, you'll want to replace the line let currentType = order[i][0].type; with let currentType = order[i][0].type.replace(/\d+$/,'');

Jeremy

Mala-in Kanyarat

unread,
May 11, 2020, 7:48:19 AM5/11/20
to ibexexperiments
Ah I am sorry I misinterpreted your messages. It now works perfeclty. Thank you very much! 
Reply all
Reply to author
Forward
0 new messages