Я заметил, что вы можете поместить различные числа внутри numpy.random.seed()
, например numpy.random.seed(1)
, numpy.random.seed(101)
. Что означают разные цифры? Как вы выбираете числа?
Какие числа я могу положить в numpy.random.seed()?
Ответ 1
Рассмотрим очень простой генератор случайных чисел:
Z[i] = (a*Z[i-1] + c) % m
Здесь Z[i]
- это случайное число ith
, a
- множитель, а c
- приращение - для разных комбинаций a
, c
и m
у вас есть разные генераторы. Это известно как линейный конгруэнтный генератор, представленный Лехмером. Остальная часть этого деления или модуля (%
) будет генерировать число между нулем и m-1
, и, установив U[i] = Z[i] / m
, вы получите случайные числа от нуля до единицы.
Как вы могли заметить, для запуска этого генеративного процесса - для того, чтобы иметь Z[1]
, вам нужно иметь Z[0]
- начальное значение. Это начальное значение, которое запускает процесс, называется семенем. Взгляните на этот пример:
Начальное значение, семя определяется как 7 для запуска процесса. Однако это значение не используется для генерации случайного числа. Вместо этого он используется для генерации первого Z
.
Наиболее важной особенностью генератора псевдослучайных чисел была бы его непредсказуемость. Как правило, до тех пор, пока вы не делитесь своим семенем, вы в порядке со всеми семенами, поскольку генераторы сегодня намного сложнее, чем это. Однако, как еще один шаг, вы также можете генерировать семя случайно. Вы можете пропустить первые цифры n
в качестве другой альтернативы.
Основной источник: Law, A. M. (2007). Моделирование и анализ моделирования. Тата Макгроу-Хилл.
Ответ 2
То, что обычно называют последовательностью случайных чисел в действительности, является "псевдослучайной" последовательностью чисел, поскольку значения вычисляются с использованием детерминированного алгоритма, и вероятность не играет никакой реальной роли.
"Семя" является отправной точкой для последовательности, и гарантией является то, что если вы начнете с одного и того же семени, вы получите ту же последовательность чисел. Это очень полезно, например, для отладки (когда вы ищете ошибку в программе, для которой вам нужно воспроизвести проблему и ее изучить, не детерминированной программе было бы гораздо сложнее отладить, потому что каждый прогон был бы иным).
Ответ 3
Короткий ответ:
Существует три способа seed()
генератора случайных чисел в numpy.random
:
-
не использовать аргумент или использовать
None
- RNG инициализируется из генератора случайных чисел ОС (что обычно является криптографически случайным) -
используйте некоторое 32-битное целое число N - RNG будет использовать это для инициализации своего состояния на основе детерминированной функции (то же самое семя → то же состояние)
-
используйте массивную последовательность из 32-разрядных целых чисел n 0, n 1, n 2 и т.д. - опять же, RNG будет использовать это для инициализации своего состояния на основе детерминированной функции (одинаковые значения для семенного и другого состояния). Это должно быть сделано с помощью хеш-функции, но в исходном коде есть магические числа, и неясно, почему они делают то, что они делают.
Если вы хотите сделать что-то повторяемое и простое, используйте одно целое.
Если вы хотите сделать что-то повторяемое, но вряд ли для третьей стороны угадать, используйте кортеж или список или массив numpy, содержащий некоторую последовательность из 32-битных целых чисел. Например, вы можете использовать numpy.random
с семенем None
для генерации пучка из 32-разрядных целых чисел (скажем, 32 из них, которые будут генерировать в общей сложности 1024 бит) из ОС RNG, хранить в некоторых seed S
, который вы сохраняете в каком-то секретном месте, затем используйте это семя для генерации любой последовательности R псевдослучайных чисел, которые вы хотите. Затем вы можете позже воссоздать эту последовательность путем повторного посева с помощью S
снова, и до тех пор, пока вы сохраняете значение S
secret (а также сгенерированные числа R), никто не сможет воспроизвести эту последовательность R Если вы просто используете одно целое число, есть только 4 миллиарда возможностей, и кто-то потенциально может их попробовать. Это может быть немного на параноидальной стороне, но вы можете это сделать.
Более длинный ответ
В модуле numpy.random
используется алгоритм Mersenne Twister, который вы можете подтвердить одним из двух способов:
-
Либо просмотрев документацию
numpy.random.RandomState
, из которыхnumpy.random
использует экземпляр дляnumpy.random.*
(но вы также можете использовать изолированный независимый экземпляр) -
Глядя на исходный код в mtrand.pyx, который использует что-то под названием Pyrex для быстрой реализации C и randomkit.c и initarray.c.
В любом случае, о чем говорится в документации numpy.random.RandomState
о seed()
:
Гарантия совместимости. Фиксированное семя и фиксированная серия вызовов методов
RandomState
, использующих одни и те же параметры, всегда будут давать одинаковые результаты до округленной ошибки, кроме случаев, когда значения были неверными. Неправильные значения будут исправлены, и версия NumPy, в которой было исправлено, будет указана в соответствующей документации. Расширение существующих диапазонов параметров и добавление новых параметров допускается, поскольку предыдущее поведение остается неизменным.Параметры:
seed: {None, int, array_like}, необязательныйСлучайное семя, используемое для инициализации генератора псевдослучайных чисел. Может быть любое целое число от 0 до 2 ** 32 - 1 включительно, массив (или другая последовательность) таких целых чисел или
None
(по умолчанию). Если семяNone
, то RandomState попытается прочитать данные из/dev/urandom
(или аналога Windows), если это доступно, или засечь из часов в противном случае.
Он не говорит, как используется семя, но если вы вникнете в исходный код, он ссылается на функцию init_by_array
: (docstring elided)
def seed(self, seed=None):
cdef rk_error errcode
cdef ndarray obj "arrayObject_obj"
try:
if seed is None:
with self.lock:
errcode = rk_randomseed(self.internal_state)
else:
idx = operator.index(seed)
if idx > int(2**32 - 1) or idx < 0:
raise ValueError("Seed must be between 0 and 2**32 - 1")
with self.lock:
rk_seed(idx, self.internal_state)
except TypeError:
obj = np.asarray(seed).astype(np.int64, casting='safe')
if ((obj > int(2**32 - 1)) | (obj < 0)).any():
raise ValueError("Seed must be between 0 and 2**32 - 1")
obj = obj.astype('L', casting='unsafe')
with self.lock:
init_by_array(self.internal_state, <unsigned long *>PyArray_DATA(obj),
PyArray_DIM(obj, 0))
И вот как выглядит функция init_by_array
:
extern void
init_by_array(rk_state *self, unsigned long init_key[], npy_intp key_length)
{
/* was signed in the original code. RDH 12/16/2002 */
npy_intp i = 1;
npy_intp j = 0;
unsigned long *mt = self->key;
npy_intp k;
init_genrand(self, 19650218UL);
k = (RK_STATE_LEN > key_length ? RK_STATE_LEN : key_length);
for (; k; k--) {
/* non linear */
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL))
+ init_key[j] + j;
/* for > 32 bit machines */
mt[i] &= 0xffffffffUL;
i++;
j++;
if (i >= RK_STATE_LEN) {
mt[0] = mt[RK_STATE_LEN - 1];
i = 1;
}
if (j >= key_length) {
j = 0;
}
}
for (k = RK_STATE_LEN - 1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i >= RK_STATE_LEN) {
mt[0] = mt[RK_STATE_LEN - 1];
i = 1;
}
}
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
self->gauss = 0;
self->has_gauss = 0;
self->has_binomial = 0;
}
Это по существу "пугает" состояние случайного числа в нелинейном хэш-подобном методе, используя каждое значение в пределах предоставленной последовательности значений затравки.
Ответ 4
В основном число гарантирует одинаковое "случайность" каждый раз.
Более правильно, число - это семя, которое может быть целым числом, массивом (или другой последовательностью) целых чисел любой длины или значением по умолчанию (none). Если seed нет, тогда случайное будет пытаться читать данные из /dev/urandom, если они доступны, или сделать семя от часов в противном случае.
Редактирование: в большинстве случаев, если ваша программа не является чем-то, что должно быть супер безопасным, не имеет значения, что вы выбираете. Если это так, не используйте эти методы - используйте os.urandom()
или SystemRandom
, если вам нужен криптографически безопасный генератор псевдослучайных чисел.
Наиболее важным понятием здесь является понимание псевдослучайности. Как только вы поймете эту идею, вы можете определить, действительно ли ваша программа нуждается в семени и т.д. Я бы рекомендовал прочитать здесь.
Ответ 5
Чтобы понять смысл случайных семян, вам нужно сначала понять "псевдослучайную" последовательность чисел, потому что значения вычисляются с использованием детерминированного алгоритма.
Таким образом, вы можете представить это число как начальное значение для вычисления следующего числа, которое вы получаете от случайного генератора. Включение такого же значения приведет к тому, что ваша программа будет получать одинаковое "случайное" значение каждый раз, поэтому ваша программа станет детерминированной.
Как сказано в этом сообщении
они (
numpy.random
иrandom.random
) используют последовательность Twister Mersenne для генерации своих случайных чисел, и они оба полностью детерминированы - то есть, если вы знаете несколько ключевых бит информации, можно предсказать с абсолютной уверенностью, какое число будет дальше.
Если вы действительно заботитесь о случайности, попросите пользователя генерировать некоторый шум (некоторые суровые слова) или просто поместите системное время в качестве семени.
Если ваши коды работают на процессоре Intel (или AMD с новейшими чипами), я также предлагаю вам проверить пакет RdRand, который использует команда cpu rdrand
для сбора "истинной" (аппаратной) случайности.
работ: