Модуль Random в Python. Генератор псевдослучайных чисел

578

Этот модуль реализует генераторы псевдослучайных чисел под различные потребности.

Для целых чисел есть выбор одного из диапазона. Для последовательностей — выбор случайного элемента, функция случайной сортировки списка и функция случайного выбора нескольких элементов из последовательности.

Есть функции для вычисления однородных, нормальных (Гауссовских), логнормальных, отрицательных экспоненциальных, гамма и бета распределений. Для генерации распределений углов доступно распределение фон Мизеса.

Почти все функции модуля зависят от основной функции random(), которая генерирует случайным образом чисто с плавающей точкой(далее float) равномерно в полуоткрытом диапазоне [0.0, 1.0). Python использует Mersenne Twister в качестве основного генератора. Он производит 53-битные точные float и имеет период 2**19937-1. Основная его реализация в C быстрая и многопоточная. Mersenne Twister один из наиболее широко протестированных генераторов случайных чисел. Однако, будучи полностью детерминированным, он подходит не для любых целей, особенно для криптографических.

Функции, предоставляемые этим модулем, связанны методами скрытого экземпляра класса random.Random. Так же можно создавать собственные экземпляры Random, для получения генераторов.

Класс Random может быть подклассом. Если вы хотите использовать другой базовый генератор своего собственного проекта: переопределите методы random (), seed (), getstate() и setstate(). Новый генератор может предоставить метод getrandbits(), что позволяет получить выборку randrange() по любому диапазону.

Модуль random так же предоставляет класс SystemRandom. Этот класс использует системную функцию os.urandom() для генерации случайных чисел из источников, которые предоставляет операционная система.

Предупреждение
Псевдослучайные генераторы этого модуля не должны использоваться в целях безопасности. Для обеспечения безопасности или для криптографического использования ознакомьтесь с модулем secrets.

Функции бухгалтерского учета

random.seed(a=None, version=2)
Инициализирует (запускает) генератор случайных чисел.
Если a не задан или None, используется текущее системное время. Если источники случайности предоставляются операционной системой, они используются вместо системного времени (см. функцию os.urandom() для получения подробной информации).
Используется значение a, если оно int (целое число).

При version=2 (по умолчанию), объекты str, bytes, или bytearray преобразуются в int и все его биты используются.

Тест на знание python

Верно ли данное утверждение: "В Python есть два типа данных: числа и строки"?
Что выведет этот код?
Модуль Random в Python. Генератор псевдослучайных чисел
Какой цикл `for` выведет такой результат?
Модуль Random в Python. Генератор псевдослучайных чисел
Модуль Random в Python. Генератор псевдослучайных чисел
Модуль Random в Python. Генератор псевдослучайных чисел
Модуль Random в Python. Генератор псевдослучайных чисел
Модуль Random в Python. Генератор псевдослучайных чисел

При version=1 (для воспроизведения случайных последовательностей из более старых версий Python), алгоритм для str и bytes
вырабатывает более узкий диапазон посева.

random.getstate()
Возвращает объект, фиксирующий текущее внутреннее состояние генератора. Этот объект может быть передан в setstate() для возобновления состояния.

random.setstate(state)
state должен быть получен из предыдущего вызова
getstate(). И setstate() восстановит внутреннее состояние генератора до такого, которое было получено из вызова getstate().

random.getrandbits(k)
Возвращает Python int со случайными битами k. Этот метод поставляется вместе с генератором MersenneTwister, в то время как другие генераторы могут также предоставлять его как необязательную часть API.
При возможности, getrandbits() включает randrange() для обработки диапазонов величины.

Функции для целых чисел

random.randrange(stop)
random.randrange(start, stop[, step])
Возвращает случайно выбранный элемент из range(start, stop, step). Это эквивалентно choice(range(start, stop, step)), но не создает объект диапазона.

Шаблон позиционного аргумента совпадает с шаблоном range(). Аргументы не должны использоваться как ключевого слова(start, stop, step), потому что функция может использовать их неожиданными способами.

random.randint(a, b)
Возвращает случайное целое число N так, чтобы a <= N <= b.

Функции для последовательностей

random.choice(seq)
Возвращает случайный элемент из непустой последовательности seq. Если seq пуст, возникает ошибка IndexError.

random.choices(population, weights=None, *, cum_weights=None, k=1)
Возвращает список элементов размером k, выбранных из population с заменой. Если population пуст, возникает ошибка IndexError.

Если задана последовательность weights, выбор производится в соответствии с относительным весом. В качестве альтернативы, если задана последовательность cum_weights, выбор производится в соответствии с совокупными весами (возможно, вычисляется с использованием itertools.accumulate()). Например, относительный вес [10, 5, 30, 5] эквивалентны кумулятивному весу [10, 15, 45, 50]. Внутренне относительные веса преобразуются в кумулятивные перед выбором, поэтому поставка кумулятивного веса экономит время.

Если ни weights, ни cum_weights не указаны, выбор производится с равной вероятностью. Если задана последовательность веса, она должна быть такой же, как и последовательность population. TypeError возникает, если не правильно указан аргумент weights или cum_weights.

Weights или cum_weights могут использовать любой тип чисел, который взаимодействует со значением float, возвращаемым функцией random() (который включает целые числа, числа с плавающей точкой и фракции, но исключает десятичные числа).

random.shuffle(x[, random])
Перемешивает последовательность x на месте.
Необязательный аргумент random — функция 0-аргумента, возвращающая случайное значение float в [0.0, 1.0]; по умолчанию это функция random().
Чтобы перемешать неизменяемую последовательность и вернуть новый перемешанный список, используйте sample(x, k=len(x)).

Обратите внимание, что даже для небольшого len(x) общее количество перестановок x может увеличиваться сильнее, чем период большинства генераторов случайных чисел.
Это означает, что большинство перестановок длинной последовательности никогда не могут быть выполнены. Например, последовательность длиной 2080 элементов является самой большой, которая может вписываться в период генератора случайных чисел Мерсин Твистер.

random.sample(population, k)
Возвращает список длиной k из уникальных элементов, выбранных из последовательности или множества. Используется для случайной выборки без замены.

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

Участники не должны быть hashable или уникальными. Если последовательность содержит повторы, то каждое вхождение является возможным выбором в выборке.

Что бы выбрать одно число из ряда чисел, используйте объект range() в качестве аргумента. Это простое решение для выборки из большой последовательности: sample(range(10000000), k=60).

Если размер выборки больше длины последовательности, возникает ошибка ValueError.

Вещественные распределения

Следующие функции генерируют конкретные вещественные распределения.
Функциональные параметры появляются после соответствующих переменных в уравнении распределения, которые используются в общей математической практике; большинство этих уравнений можно найти в любом статистическом тексте.

random.random()
Возвращает случайное число с плавающей точкой в диапазоне [0.0, 1.0).

random.uniform(a, b)
Возвращает случайное число с плавающей точкой N таким образом, чтобы a <= N <= b для a <= b и b <= N <= a для b < a.

Конечное значение b будет или не будет включено в диапазон в зависимости от округления float в уравнении a + (b-a) * random().

random.triangular(low, high, mode)
Возвращает случайное число с плавающей точкой N, так, что low <= N <= high и с указанным mode между этими границами. Границы low и high по умолчанию равны 0 и 1.
Аргумент mode по умолчанию совпадает с серединой между границами, предоставляя симметричное распределение.

random.betavariate(alpha, beta)
Бета-распределение. Условиями для аргументов являются alpha > 0 и beta > 0. Возвращаемые значения варьируются от 0 до 1.

random.expovariate(lambd)
Экспоненциальное распределение. lambd равно 1.0, деленное на желаемое среднее значение. Оно должно быть отличным от нуля (Параметр будет называться «лямбда», но это зарезервированное слово в Python). Возвращаемые значения варьируются от 0 до положительной бесконечности, если lambd положительный, и от отрицательной бесконечности до 0, если lambd отрицателен.

random.gammavariate(alpha, beta)
Гамма-распределение (Не гамма-функция!). Условиями для параметров являются alpha > 0 и beta > 0.

Функция распределения вероятности:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha

random.gauss(mu, sigma)
Гауссовское распределение. mu — среднее значение, а sigma — стандартное отклонение. Она немного быстрее, чем функция normalvariate(), обозначенная ниже.

random.lognormvariate(mu, sigma)
Нормальное распределение логарифма. Если вы берете натуральный логарифм этого распределения, вы получите нормальное распределение со средним mu и стандартным отклонением sigma. mu может иметь любое значение, а sigma должно быть больше нуля.

random.normalvariate(mu, sigma)
Нормальное распределение. mu — среднее значение, а sigma — стандартное отклонение.

random.vonmisesvariate(mu, kappa)
mu — средний угол, выраженный в радианах от 0 до 2pi, а kappa — параметр концентрации, который должен быть больше или равен нулю.
Если kappa равен нулю, это распределение сводится к равномерному случайному углу в диапазоне от 0 до 2
pi.

random.paretovariate(alpha)
Распределение Парето. alpha — параметр формы.

random.weibullvariate(alpha, beta)
Распределение Вейбулла. alpha — параметр масштаба, а beta — параметр формы.

Альтернативный генератор

Класс random.SystemRandom([seed])
Класс, который использует функцию os.urandom() для генерации случайных чисел из источников, предоставляемых операционной системой. Не доступен для всех систем. Не полагается на состояние программного обеспечения, последовательности не воспроизводятся. Следовательно методу seed() не имеет эффекта и игнорируется. При вызове методов getstate() и setstate() возникает ошибка NotImplementedError.

Примеры и инструкции

Базовые примеры:

>>> random()                             # Случайное float:  0.0 <= x < 1.0
0.37444887175646646

>>> uniform(2.5, 10.0)                   # Случайное float:  2.5 <= x < 10.0
3.1800146073117523

>>> expovariate(1 / 5)                   # Интервал между прибытием в среднем 5 секунд
5.148957571865031

>>> randrange(10)                        # Целое число от 0 до 9 включительно
7

>>> randrange(0, 101, 2)                 # Четное целое число от 0 до 100 включительно
26

>>> choice(['win', 'lose', 'draw'])      # Случайный элемент из последовательности
'draw'

>>> deck = 'ace two three four'.split()
>>> shuffle(deck)                        # Перемешать список
>>> deck
['four', 'two', 'ace', 'three']

>>> sample([10, 20, 30, 40, 50], k=4)    # Четыре элемента без замены
[40, 10, 50, 30]

Симуляторы:

>>>>>> # Шесть резуьтатов рулетки (взвешенная выборка с заменой)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']
>>> # Задействуйте 20 карт без замены колоды из 52 игральных карт
>>> # и определите долю карт с десятизначным значением
>>> # (десятка, валет, королева или король).
>>> deck = collections.Counter(tens=16, low_cards=36)
>>> seen = sample(list(deck.elements()), k=20)
>>> seen.count('tens') / 20
0.15
>>> # Оцените вероятность получения 5 или более побед из 7 спинов
>>> # смещенной монеты, которая располагается наверху в 60% случаев.
>>> trial = lambda: choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
>>> sum(trial() for i in range(10000)) / 10000
0.4169
>>> # Вероятность медианы 5 образцов, находящихся в средних двух квартилях
>>> trial = lambda : 2500 <= sorted(choices(range(10000), k=5))[2]  < 7500
>>> sum(trial() for i in range(10000)) / 10000
0.7958