У меня есть два массива разных форм, но одинаковой длины (начальный размер). Я хочу перетасовать каждый из них так, чтобы соответствующие элементы продолжали соответствовать - т.е. перетасовывать их в унисон относительно их ведущих показателей.
Этот код работает и иллюстрирует мои цели:
def shuffle_in_unison(a, b):
assert len(a) == len(b)
shuffled_a = numpy.empty(a.shape, dtype=a.dtype)
shuffled_b = numpy.empty(b.shape, dtype=b.dtype)
permutation = numpy.random.permutation(len(a))
for old_index, new_index in enumerate(permutation):
shuffled_a[new_index] = a[old_index]
shuffled_b[new_index] = b[old_index]
return shuffled_a, shuffled_b
Например:
>>> a = numpy.asarray([[1, 1], [2, 2], [3, 3]])
>>> b = numpy.asarray([1, 2, 3])
>>> shuffle_in_unison(a, b)
(array([[2, 2],
[1, 1],
[3, 3]]), array([2, 1, 3]))
Однако это кажется неуклюжим, неэффективным и медленным, и требует создания копии массивов - я бы предпочел перетасовать их на месте, так как они будут довольно большими.
Есть ли лучший способ сделать это? Мои основные цели - более быстрое выполнение и меньшее использование памяти, но элегантный код тоже подойдет.
Еще одна мысль у меня была такая:
def shuffle_in_unison_scary(a, b):
rng_state = numpy.random.get_state()
numpy.random.shuffle(a)
numpy.random.set_state(rng_state)
numpy.random.shuffle(b)
Это работает ... но это немного страшно, так как я вижу небольшую гарантию, что оно продолжит работать - это не похоже на то, что гарантированно выживет, например, в простой версии.
Ответы:
Ваше "страшное" решение не кажется мне пугающим. Вызов
shuffle()
двух последовательностей одинаковой длины приводит к одинаковому количеству обращений к генератору случайных чисел, и это единственные «случайные» элементы в алгоритме тасования. Сбрасывая состояние, вы гарантируете, что вызовы генератора случайных чисел дадут одинаковые результаты во втором вызовеshuffle()
, поэтому весь алгоритм будет генерировать одну и ту же перестановку.Если вам это не нравится, другое решение будет хранить ваши данные в одном массиве вместо двух с самого начала и создавать два представления в этом одном массиве, имитируя два имеющихся у вас массива. Вы можете использовать один массив для перемешивания и представления для всех других целей.
Пример: Давайте предположим , что массивы
a
иb
выглядеть следующим образом :Теперь мы можем построить один массив, содержащий все данные:
Теперь мы создаем виды, имитирующие оригинал
a
иb
:Данные
a2
иb2
передаются сc
. Чтобы перемешать оба массива одновременно, используйтеnumpy.random.shuffle(c)
.В рабочем коде вы, конечно, постараетесь избежать создания оригинала
a
и сразуb
и сразу же создатьc
,a2
иb2
.Это решение может быть адаптировано к случаю того, что
a
иb
имеют разные типы.источник
numpy.random.shuffle()
работает с произвольными изменяемыми последовательностями, такими как списки Python или массивы NumPy. Форма массива не имеет значения, только длина последовательности. Это очень вряд ли изменится на мой взгляд.Вы можете использовать индексирование массива NumPy :
Это приведет к созданию отдельных массивов в случайном порядке.
источник
>>> t = timeit.Timer(stmt = "<function>(a,b)", setup = "import numpy as np; a,b = np.arange(4), np.arange(4*20).reshape((4,20))")>>> t.timeit()
и получил 38 секунд для версии ОП, и 27,5 секунд для моей, по 1 миллиону вызовов каждый.a.shape
есть(31925, 405)
иb.shape
есть(31925,)
.Чтобы узнать больше, см. Http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html.
источник
Очень простое решение:
два массива x, y теперь оба случайно перемешиваются одинаково
источник
Джеймс написал в 2015 году решение sklearn, которое полезно. Но он добавил случайную переменную состояния, которая не нужна. В приведенном ниже коде случайное состояние из numpy принимается автоматически.
источник
источник
Перемешайте любое количество массивов на месте, используя только NumPy.
И можно использовать как это
Несколько вещей, на которые стоит обратить внимание:
После перемешивания данные могут быть разделены с
np.split
использованием срезов или ссылки на них - в зависимости от приложения.источник
RandomState
может быть использован за пределами цикла. См. Ответfor
цикле, - переназначить или повторно установить случайное состояние. С ожидаемым небольшим числом массивов, передаваемых в функцию тасования, я не ожидаю разницы в производительности между ними. Но да, rstate можно назначать вне цикла и повторно вводить в цикле на каждой итерации.Вы можете сделать массив как:
тогда перемешайте это:
теперь используйте это s в качестве аргумента ваших массивов. одни и те же перемешанные аргументы возвращают одинаковые перемешанные векторы.
источник
Один из способов, которым можно сделать перемешивание на месте для связанных списков, - это использовать начальное число (оно может быть случайным) и использовать numpy.random.shuffle для выполнения перемешивания.
Вот и все. Это перетасует и a и b точно таким же образом. Это также делается на месте, что всегда является плюсом.
РЕДАКТИРОВАТЬ, не используйте np.random.seed (), используйте вместо этого np.random.RandomState
При его вызове просто передайте любое начальное число для подачи случайного состояния:
Вывод:
Редактировать: Исправлен код для повторного заполнения случайного состояния
источник
RandomState
изменяет свое состояние по первому зову иa
иb
не перемешиваются в унисон.Существует хорошо известная функция, которая может справиться с этим:
Просто установив test_size в 0, вы избежите разделения и получите перемешанные данные. Хотя обычно он используется для разделения данных обучения и тестирования, он также перемешивает их.
Из документации
источник
Скажем, у нас есть два массива: a и b.
Мы можем сначала получить индексы строки, переставляя первое измерение
Тогда используйте расширенную индексацию. Здесь мы используем одни и те же индексы, чтобы перетасовать оба массива в унисон.
Это эквивалентно
источник
Если вы хотите избежать копирования массивов, я бы предложил вместо генерации списка перестановок пройтись по каждому элементу в массиве и случайным образом поменять его на другую позицию в массиве.
Это реализует алгоритм перемешивания Кнута-Фишера-Йейтса.
источник
len(a)
наreversed(range(1, len(a)))
. Но это все равно будет не очень эффективно.Это кажется очень простым решением:
источник
С примером, это то, что я делаю:
источник
combo = zip(images, labels); shuffle(combo); im, lab = zip(*combo)
, просто медленнее. Так как вы все равно используете Numpy, гораздо более быстрым решением было бы сжать массивы с помощью Numpycombo = np.c_[images, labels]
, shuffle и снова разархивироватьimages, labels = combo.T
. Предполагая, чтоlabels
иimages
являются одномерными массивами Numpy одинаковой длины, для начала это будет легко самым быстрым решением. Если они многомерны, см. Мой ответ выше.Я расширил Python random.shuffle (), чтобы взять второй аргумент:
Таким образом, я могу быть уверен, что перетасовка происходит на месте, а функция не слишком длинная и не сложная.
источник
Просто используйте
numpy
...Сначала объедините два входных массива 1D-массив - это метки (y), а 2D-массив - это данные (x) и перемешайте их
shuffle
методом NumPy . Наконец разделите их и вернитесь.источник