Last active
July 21, 2021 19:00
-
-
Save jdkoen/2e94645a086477896daa1726fe3324c7 to your computer and use it in GitHub Desktop.
This is a script that creates a randomized list of stimuli (here, faces, scenes, and objects), that are repeated with a lag in a specified range. This is generic and can be modified for more complex constraints.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import pandas as pd | |
from random import shuffle | |
from pathlib import Path | |
# Out directory | |
out_dir = Path('lagged_lists') | |
out_dir.mkdir(exist_ok=True) | |
# Make a dummy stimulus list | |
n_stim_per_group = 120 # Number of stimuli per grouping factor | |
face_list = [f'face-{x:03}' for x in np.arange(n_stim_per_group)] | |
scene_list = [f'scene-{x:03}' for x in np.arange(n_stim_per_group)] | |
object_list = [f'object-{x:03}' for x in np.arange(n_stim_per_group)] | |
stim_list = pd.DataFrame({'trial': face_list + scene_list + object_list}) | |
n_trials = len(stim_list) * 2 | |
# Options for controlling the lag | |
min_lag = 10 # Minimum lag between repeats (number of trials between, not including repeat) | |
max_lag = 50 # Maximum lag between repeats (number of trials between, not including repeat) | |
t1_cutoff = n_trials - min_lag # Avoids 1st presentation being in an impossible spot | |
n_lists_needed = 1 # How many lists are needed | |
# Start a while loop to find good randomizations | |
# Note: if a iteration fails to place all items in a spot with an | |
# in range lag, the randomization is ignored and it starts a new | |
# randomization. It goes until the number of good lists/randomizations | |
# found equals the number of lists needed (n_lists_needed) | |
good_lists = 0 # Keeps track of good lists. | |
while good_lists != n_lists_needed: | |
# Randomize the stim_list | |
stim_list = stim_list.sample(frac=1) | |
# Make an 'empty' data frame | |
trials = pd.DataFrame({'trial': [''] * n_trials}) # Makes empty data frame | |
# Loop through all the trials in the (randomized) stim list | |
# To find a home for them | |
for i, row in stim_list.iterrows(): | |
# Find empty rows/trials that have not been assigned | |
open_rows = np.where(trials.applymap(lambda x: x == ''))[0] | |
# Make a copy of open_rows and remove unneeded ones | |
# The 1 is for the 1st presentation | |
open_rows1 = open_rows.copy() | |
open_rows1 = open_rows1[open_rows1 < t1_cutoff] | |
# Search through the open rows (open_rows1) | |
while True: | |
# Break the loop if no more valid open rows for | |
# 1st repetition | |
# Note: open_rows1 changes shape if no valid | |
# lags are found below, so it can continue, and | |
# fail, only when there are no valid positionings | |
# for any single trial | |
if open_rows1.shape[0] == 0: | |
break | |
# Select a first row and remove from open_rows1 | |
first_row = open_rows1[0] | |
open_rows1 = open_rows1[open_rows1 != first_row] | |
# Find the possible lags, and omit lags that have been filled | |
min_row = first_row + min_lag + 1 # Plus 1 for min_lag spacing | |
max_row = first_row + max_lag + 2 # Plus 2 for max_lag spacing | |
possible_lags = np.arange(min_row, max_row) | |
possible_lags = [x for x in possible_lags if x in open_rows] | |
possible_lags = np.array(possible_lags) | |
# If there are no possibl lags, skip this first trial position | |
# Otherwise, randomly select a valid lag | |
if possible_lags.shape[0] == 0: | |
continue # Move to next iteration | |
else: | |
shuffle(possible_lags) | |
second_row = possible_lags[0] | |
trials['trial'].iloc[first_row] = row['trial'] | |
trials['trial'].iloc[second_row] = row['trial'] | |
break | |
# One the for loop is done, see if there are still empty values in trials. | |
# If there are, then it is not a good_list and nothing is done. | |
# If, however, there are no blanks (which is the convoluted if conditional), | |
# then it is a good list which is written to a csv file. | |
if np.where(trials.applymap(lambda x: x == ''))[0].shape[0] == 0: | |
good_lists += 1 | |
print('# Good Lists:', good_lists) | |
trials.to_csv(out_dir / f'list{good_lists}.csv', index=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment