#python #arrays #numpy #shuffle
#python #массивы #numpy #перетасовать
Вопрос:
У меня есть массив numpy, и я хотел бы перетасовать его части. Например, со следующим массивом:
import numpy as np
import random
a = np.arange(15)
# => array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
Я хочу сделать:
shuffle_parts(a, [(0, 3), (10, 13)])
# => array([ 2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 12, 11, 10, 13, 14])
# ^^^^^^^^^ ^^^^^^^^^^
# Shuffle those 3 values and those 3 values
Следующее перетасовало бы весь массив: (Не то, что я хочу)
random.shuffle(a)
# => array([10, 11, 8, 1, 13, 5, 9, 14, 4, 7, 2, 12, 3, 0, 6])
Одним из способов было бы использовать разделение / объединение следующим образом:
splits = np.split(a, 5)
random.shuffle(splits[0])
random.shuffle(splits[3])
np.concatenate(splits)
# => array([ 2, 0, 1, 3, 4, 5, 6, 7, 8, 11, 10, 9, 12, 13, 14])
# ^^^^^^^^^ ^^^^^^^^^^
# Correctly shuffled Shuffled but off by 1 index
Это почти то, чего я хочу. Мои вопросы:
- Могу ли я написать,
shuffle_parts
где индексы являются пользовательскими (части с произвольными индексами, не ограниченные модулями, и части с различной длиной) - Есть ли в numpy метод, который я пропустил, и который помог бы мне это сделать?
Комментарии:
1. Просто перетасуйте нарезанные представления массива, например
np.random.shuffle(a[0:3])
Ответ №1:
Это можно сделать напрямую:
>>> import numpy as np
>>> import random
>>> a = np.arange(15)
>>> s=3
>>> f=7
>>> random.shuffle(a[s:f])
>>> a
array([ 0, 1, 2, 5, 4, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14])
Индексирование напрямую ссылается на данные, что делает это возможным.
Комментарии:
1. Мой код выполняется внутри параллельно работающих workers, и я заметил, что все случайные значения в конечном итоге одинаковы (для данного рабочего пакета). Если я инициализирую случайное начальное значение с рабочим индексом, это решает эту проблему. Я не знаю, об этом ли вы предупреждаете.
2. @BenjaminCrouzier Нет, случайный алгоритм сам по себе «небезопасен». Я не думаю, что это должно иметь значение, хотя для программ, которым просто нужна некоторая случайность в них. Я отметил это на случай, если вы захотите прочитать больше.
3. Вы путаете случайность и безопасность. Python (и в расширении numpy) использует генератор псевдослучайных чисел, поэтому он небезопасен для криптографических целей. Для всего остального это просто отлично. Это не слабость или недостаток библиотеки или языка — это то же самое на любом другом языке. Если вам нужны действительно случайные числа, они должны поступать из действительно случайного источника, а не из алгоритма (и если вы не знаете, есть ли у вас, вы этого не делаете).
4. @user2699 Очень хорошо, я не хотел вдаваться в такие глубины, но конец вашего комментария, я думаю, подтверждает вашу точку зрения — я отредактирую примечание.
Ответ №2:
фрагменты numpy — это представления приведенных ниже данных; поэтому вы можете напрямую перетасовывать фрагменты:
import numpy as np
import random
a = np.arange(15)
random.shuffle(a[0:3])
random.shuffle(a[10:13])
print(a)
# [ 2 0 1 3 4 5 6 7 8 9 12 10 11 13 14]
тогда вы могли бы реализовать свою shuffle_parts
функцию, используя slice
этот способ:
def shuffle_parts(array, slices):
for s in slices:
random.shuffle(a[slice(*s)])
shuffle_parts(array=a, slices=((0, 3), (10, 13)))
или (в зависимости от того, как вы хотите передать фрагменты в вашу функцию):
def shuffle_parts(array, slices):
for s in slices:
random.shuffle(a[s])
shuffle_parts(array=a, slices=(slice(0, 3), slice(10, 13)))
лично я бы предпочел вторую версию (таким образом, вы также могли бы, например, перетасовать четные индексы: shuffle_parts(array=a, slices=(slice(None, None, 2), ))
)…