Мой алгоритм перемешивания дает сбой, когда испытаний больше, чем объектов

Я пытаюсь провести эксперимент, в котором папка сканируется на наличие изображений. Для каждого испытания отображается цель и несколько (7) изображений дистрактора. После этого в половине испытаний людям показывают целевое изображение, а в другой половине - изображение, которого не было на предыдущем дисплее.

Мой текущий код вроде работает, но только если испытаний меньше, чем объектов:

repeats = 20

# Scan dir for images
jpgs = []

for path, dirs, files in os.walk(directory):
    for f in files:
        if f.endswith('.jpg'):
            jpgs.append(f)

# Shuffle up jpgs
np.random.shuffle(jpgs)

# Create list with target and probe object, Half random, half identical
display = []
question = []
sameobject = []
position = np.repeat([0,1,2,3,4,5,6,7], repeats)
for x in range(1,(repeats*8)+1):
    display.append(jpgs[x])
    if x % 2 == 0:
        question.append(jpgs[-x])
        sameobject.append(0)
    else:
        question.append(jpgs[x])
        sameobject.append(1)

# Concatonate objects together
together = np.c_[display,question,position,sameobject] 
np.random.shuffle(together)

for x in together:
        # Shuffle and set image
        np.random.shuffle(jpgs)
        myList = [i for i in jpgs if i != together[trial,0]]
        myList = [i for i in myList if i != together[trial,1]]

        # Set correct image for target
        myList[int(together[trial,2])] = together[trial,0]

Прежде всего, я понимаю, что это ужасный код. Но он выполняет свою работу грубо. С 200 JPG и повторением 20 он работает. Если повторение установлено на 30, происходит сбой.

Вот пример с слишком большим повторением:

  File "H:\Code\Stims\BetaObjectPosition.py", line 214, in <module>
    display.append(jpgs[x])
IndexError: list index out of range

Есть ли способ обновить мой код таким образом, чтобы разрешить больше испытаний, в то время как все объекты используются как можно более равномерно (один объект не должен отображаться 3 раза, а другой отображается 0) в течение всего эксперимента?

Полный воспроизводимый пример

Бонусные баллы, если кто-то может увидеть очевидный способ сбалансировать способ выбора 7 отвлекающих изображений.

Спасибо, что нашли время прочитать это. Надеюсь, ты сможешь мне помочь.


person Simon Hviid Del Pin    schedule 13.07.2018    source источник
comment
Вы разместили полный код для воспроизведения вашей проблемы? По крайней мере, импорт отсутствует. Очень помогает опубликовать минимальный, полный и проверяемый пример. Не могли бы вы также предоставить сообщение об ошибке, которое вы получаете?   -  person Viktor Seifert    schedule 13.07.2018
comment
Как я понимаю: вы хотите использовать jpeg-изображения в случайном порядке. Если повторов больше, чем изображений, изображения следует использовать повторно, но перемешать по-другому. Это верно?   -  person Viktor Seifert    schedule 13.07.2018
comment
@ViktorSeifert благодарим за отзыв. Да, похоже, вы правильно поняли. Я добавил ошибку и посмотрю, смогу ли я сделать код воспроизводимым, если он все еще понадобится.   -  person Simon Hviid Del Pin    schedule 13.07.2018


Ответы (1)


Решение, которое меньше всего изменяет ваш код, должно заключаться в изменении каждого вызова jpgs[x] на jpgs[x % len(jpgs)] 1. Это должно избавить от IndexError; он в основном оборачивает индекс списка «по краям», чтобы он никогда не был слишком большим. Хотя я не уверен, как он будет взаимодействовать с вызовом jpgs[-x].

Альтернативой может быть реализация класса, который производит более длинную последовательность объектов из более короткой. Пример:

from random import shuffle


class InfiniteRepeatingSequence(object):
  def __init__(self, source_list):
      self._source = source_list
      self._current = []

  def next(self):
      if len(self._current) == 0:
          # copy the source
          self._current = self._source[:]

          shuffle(self._current)

      # get and remove an item from a list
      return self._current.pop()

Этот класс повторяет список до бесконечности. Он обязательно использует каждый элемент один раз перед повторным использованием списка. Его легко превратить в итератор (попробуйте заменить next на __next__). Но будьте осторожны, поскольку приведенный выше класс создает бесконечную последовательность элементов.


1 См. «Как% работает в Python?» для объяснения оператора по модулю.

Изменить: добавлена ​​ссылка на вопрос по модулю.

person Viktor Seifert    schedule 13.07.2018
comment
Спасибо за отзыв, Виктор. Ваше решение с использованием jpgs [x% len (jpgs)] ПОЧТИ именно то, на что я надеялся. Проблема в том, что он дает несколько ошибок с вызовом jpgs [-x], как вы и опасались. Я добавил несколько строк внизу своего кода, и с 200 изображениями в моем каталоге он постоянно дает мне 3 ошибки с 40 повторениями. Я посмотрю, смогу ли я решить этот вопрос сам, но, конечно, очень приветствую ваш вклад :) pastebin.com/nzv3psje - person Simon Hviid Del Pin; 16.07.2018