random
— Генерирование псевдослучайных чисел¶
Исходный код: Lib/random.py.
Этот модуль реализует генераторы псевдослучайных чисел для различных дистрибутивов.
Для целых чисел - равномерный выбор из диапазона. Для последовательностей есть равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без замены.
На вещественной прямой имеются функции для вычисления равномерного, нормального (гауссова), логнормального, отрицательного экспоненциального, гамма- и бета-распределения. Для генерации распределений углов доступно распределение фон Мизеса.
Почти все функции модуля зависят от базовой функции random()
, которая генерирует случайное плавающее число равномерно в полуоткрытом диапазоне [0.0, 1.0). В качестве базового генератора в Python используется твистер Мерсенна. Он производит 53-битные плавающие числа точности и имеет период 2**19937-1. Базовая реализация на языке C является быстрой и потокобезопасной. Mersenne Twister - один из наиболее интенсивно тестируемых генераторов случайных чисел. Однако, будучи полностью детерминированным, он не подходит для всех целей, и совершенно не подходит для криптографических целей.
Функции, предоставляемые этим модулем, на самом деле являются связанными методами скрытого экземпляра класса random.Random
. Вы можете создавать свои собственные экземпляры Random
для получения генераторов, не разделяющих состояние.
Класс Random
также может быть подклассом, если вы хотите использовать другой базовый генератор собственного изобретения: в этом случае переопределите методы random()
, seed()
, getstate()
и setstate()
. Как вариант, новый генератор может предоставить метод getrandbits()
- это позволяет randrange()
производить выборки в произвольно большом диапазоне.
Модуль random
также предоставляет класс SystemRandom
, который использует системную функцию os.urandom()
для генерации случайных чисел из источников, предоставляемых операционной системой.
Предупреждение
Псевдослучайные генераторы этого модуля не следует использовать в целях безопасности. Для использования в целях безопасности или криптографии смотрите модуль secrets
.
См.также
M. Мацумото и Т. Нишимура, «Mersenne Twister: 623-мерный равнораспределенный равномерный генератор псевдослучайных чисел», ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.3–30 1998.
Complementary-Multiply-with-Carry recipe для совместимого альтернативного генератора случайных чисел с большим периодом и сравнительно простыми операциями обновления.
Бухгалтерские функции¶
-
random.
seed
(a=None, version=2)¶ Инициализация генератора случайных чисел.
Если a опущено или
None
, используется текущее системное время. Если источники случайности предоставляются операционной системой, они используются вместо системного времени (подробнее о доступности см. в функцииos.urandom()
).Если a - это int, то оно используется напрямую.
В версии 2 (по умолчанию) объект
str
,bytes
илиbytearray
преобразуется вint
и используются все его биты.В версии 1 (предоставляемой для воспроизведения случайных последовательностей из старых версий Python) алгоритм для
str
иbytes
генерирует более узкий диапазон семян.Изменено в версии 3.2: Перешли на схему версии 2, которая использует все биты в строковом семени.
-
random.
getstate
()¶ Возвращает объект, фиксирующий текущее внутреннее состояние генератора. Этот объект может быть передан в
setstate()
для восстановления состояния.
-
random.
setstate
(state)¶ state должно было быть получено из предыдущего вызова
getstate()
, аsetstate()
восстанавливает внутреннее состояние генератора до того, каким оно было на момент вызоваgetstate()
.
Функции для байтов¶
-
random.
randbytes
(n)¶ Сгенерируйте n случайных байтов.
Этот метод не следует использовать для генерации маркеров безопасности. Вместо этого используйте
secrets.token_bytes()
.Добавлено в версии 3.9.
Функции для целых чисел¶
-
random.
randrange
(stop)¶ -
random.
randrange
(start, stop[, step]) Возвращает случайно выбранный элемент из
range(start, stop, step)
. Это эквивалентноchoice(range(start, stop, step))
, но на самом деле не строит объект диапазона.Шаблон позиционного аргумента соответствует шаблону
range()
. Аргументы с ключевыми словами не следует использовать, поскольку функция может использовать их неожиданным образом.Изменено в версии 3.2:
randrange()
является более сложным для получения равномерно распределенных значений. Раньше использовался стильint(random()*n)
, который мог давать немного неравномерное распределение.Не рекомендуется, начиная с версии 3.10: Автоматическое преобразование нецелых типов в эквивалентные целые числа устарело. В настоящее время
randrange(10.0)
без потерь преобразуется вrandrange(10)
. В будущем это будет вызывать ошибкуTypeError
.Не рекомендуется, начиная с версии 3.10: Исключение, возникающее для неинтегральных значений, таких как
randrange(10.5)
илиrandrange('10')
, будет изменено сValueError
наTypeError
.
-
random.
randint
(a, b)¶ Возвращает случайное целое число N такое, что
a <= N <= b
. Псевдоним дляrandrange(a, b+1)
.
-
random.
getrandbits
(k)¶ Возвращает неотрицательное целое число Python с k случайными битами. Этот метод поставляется с генератором MersenneTwister, и некоторые другие генераторы могут также предоставлять его в качестве дополнительной части API. Когда доступно,
getrandbits()
позволяетrandrange()
обрабатывать произвольно большие диапазоны.Изменено в версии 3.9: Теперь этот метод принимает ноль для k.
Функции для последовательностей¶
-
random.
choice
(seq)¶ Возвращает случайный элемент из непустой последовательности seq. Если seq пуст, то выдает
IndexError
.
-
random.
choices
(population, weights=None, *, cum_weights=None, k=1)¶ Возвращает список размером k элементов, выбранных из населения с заменой. Если популяция пуста, выдает
IndexError
.Если указана последовательность weights, выборка производится в соответствии с относительными весами. В качестве альтернативы, если задана последовательность cum_weights, то отбор производится в соответствии с суммарными весами (возможно, вычисленными с помощью
itertools.accumulate()
). Например, относительные веса[10, 5, 30, 5]
эквивалентны кумулятивным весам[10, 15, 45, 50]
. Внутри программы относительные веса преобразуются в кумулятивные перед выполнением выбора, поэтому предоставление кумулятивных весов экономит работу.Если не указаны ни weights, ни cum_weights, выборки производятся с равной вероятностью. Если указана последовательность весов, она должна быть той же длины, что и последовательность популяции. Указать и весы, и сумму_весов - это
TypeError
.В weights или cum_weights может использоваться любой числовой тип, который взаимодействует со значениями
float
, возвращаемымиrandom()
(сюда входят целые, плавающие и дробные числа, но не входят десятичные). Предполагается, что веса неотрицательны и конечны. Если все веса равны нулю, выдается сообщениеValueError
.Для заданного семени функция
choices()
с равным весом обычно выдает другую последовательность, чем повторные вызовыchoice()
. Алгоритм, используемыйchoices()
, использует арифметику с плавающей запятой для внутренней согласованности и скорости. Алгоритм, используемыйchoice()
, по умолчанию использует целочисленную арифметику с повторными выборами, чтобы избежать небольших смещений из-за ошибки округления.Добавлено в версии 3.6.
Изменено в версии 3.9: Вызывает ошибку
ValueError
, если все веса равны нулю.
-
random.
shuffle
(x[, random])¶ Перемешайте последовательность x на месте.
Необязательный аргумент random - это 0-аргументная функция, возвращающая случайное число в [0.0, 1.0]; по умолчанию это функция
random()
.Чтобы перетасовать неизменяемую последовательность и вернуть новый перетасованный список, используйте
sample(x, k=len(x))
вместо этого.Обратите внимание, что даже при малых
len(x)
общее число перестановок x может быстро стать больше, чем период большинства генераторов случайных чисел. Это означает, что большинство перестановок длинной последовательности никогда не может быть сгенерировано. Например, последовательность длиной 2080 - самая большая, которая может уложиться в период генератора случайных чисел Mersenne Twister.Deprecated since version 3.9, will be removed in version 3.11: Необязательный параметр random.
-
random.
sample
(population, k, *, counts=None)¶ Возвращает список длиной k уникальных элементов, выбранных из последовательности или множества популяции. Используется для случайной выборки без замены.
Возвращает новый список, содержащий элементы из совокупности, оставляя исходную совокупность неизменной. Полученный список располагается в порядке выбора, так что все подвыборки также будут действительными случайными выборками. Это позволяет разделить победителей лотереи (выборку) на обладателей главного приза и второго места (подвыборки).
Члены популяции не обязательно должны быть hashable или уникальными. Если совокупность содержит повторы, то каждое повторение является возможным отбором в выборку.
Повторяющиеся элементы могут быть указаны по одному или с помощью необязательного параметра counts, содержащего только ключевое слово. Например,
sample(['red', 'blue'], counts=[4, 2], k=5)
эквивалентноsample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)
.Чтобы выбрать выборку из диапазона целых чисел, используйте в качестве аргумента объект
range()
. Это особенно быстро и экономит место при выборке из большой популяции:sample(range(10000000), k=60)
.Если размер выборки больше размера популяции, выдается сообщение
ValueError
.Изменено в версии 3.9: Добавлен параметр counts.
Распределения с реальными значениями¶
Следующие функции генерируют определенные распределения вещественных величин. Параметры функций названы по соответствующим переменным в уравнении распределения, используемом в обычной математической практике; большинство этих уравнений можно найти в любом тексте по статистике.
-
random.
random
()¶ Возвращает следующее случайное число с плавающей точкой в диапазоне [0.0, 1.0].
-
random.
uniform
(a, b)¶ Возвращает случайное число с плавающей точкой N такое, что
a <= N <= b
дляa <= b
иb <= N <= a
дляb < a
.Значение конечной точки
b
может быть включено или не включено в диапазон в зависимости от округления с плавающей точкой в уравненииa + (b-a) * random()
.
-
random.
triangular
(low, high, mode)¶ Возвращает случайное число с плавающей точкой N такое, что
low <= N <= high
и с заданным режимом между этими границами. Границы low и high по умолчанию равны нулю и единице. Аргумент 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()
, определенная ниже.Примечание по многопоточности: Когда два потока одновременно вызывают эту функцию, возможно, что они получат одно и то же возвращаемое значение. Этого можно избежать тремя способами. 1) Пусть каждый поток использует свой экземпляр генератора случайных чисел. 2) Наложить блокировки на все вызовы. 3) Использовать более медленную, но безопасную для потоков функцию
normalvariate()
.
-
random.
lognormvariate
(mu, sigma)¶ Логарифмически нормальное распределение. Если взять натуральный логарифм этого распределения, то получится нормальное распределение со средним mu и стандартным отклонением sigma. mu может иметь любое значение, а sigma должна быть больше нуля.
-
random.
normalvariate
(mu, sigma)¶ Нормальное распределение. mu - среднее значение, а sigma - стандартное отклонение.
-
random.
vonmisesvariate
(mu, kappa)¶ mu - средний угол, выраженный в радианах в диапазоне от 0 до 2*pi, а kappa - параметр концентрации, который должен быть больше или равен нулю. Если kappa равна нулю, это распределение сводится к равномерному случайному углу в диапазоне от 0 до 2*pi.
-
random.
paretovariate
(alpha)¶ Распределение Парето. alpha - это параметр формы.
-
random.
weibullvariate
(alpha, beta)¶ Распределение Вейбулла. альфа - параметр масштаба, а бета - параметр формы.
Альтернативный генератор¶
-
class
random.
Random
([seed])¶ Класс, реализующий генератор псевдослучайных чисел по умолчанию, используемый модулем
random
.
-
class
random.
SystemRandom
([seed])¶ Класс, использующий функцию
os.urandom()
для генерации случайных чисел из источников, предоставляемых операционной системой. Доступен не во всех системах. Не полагается на состояние программного обеспечения, и последовательности не воспроизводятся. Соответственно, методseed()
не имеет эффекта и игнорируется. Методыgetstate()
иsetstate()
при вызове вызывают ошибкуNotImplementedError
.
Заметки о воспроизводимости¶
Иногда полезно иметь возможность воспроизводить последовательности, выдаваемые генератором псевдослучайных чисел. Повторное использование значения затравки позволяет воспроизводить одну и ту же последовательность от запуска к запуску, пока не запущено несколько потоков.
Большинство алгоритмов и функций посева модуля random подвержены изменениям в разных версиях Python, но два аспекта гарантированно не изменятся:
Если добавляется новый метод посева, то будет предложена сеялка с обратной совместимостью.
Метод генератора
random()
будет продолжать производить ту же самую последовательность, когда совместимому сеятелю дается тот же самый посевной материал.
Примеры¶
Основные примеры:
>>> random() # Random float: 0.0 <= x < 1.0
0.37444887175646646
>>> uniform(2.5, 10.0) # Random float: 2.5 <= x <= 10.0
3.1800146073117523
>>> expovariate(1 / 5) # Interval between arrivals averaging 5 seconds
5.148957571865031
>>> randrange(10) # Integer from 0 to 9 inclusive
7
>>> randrange(0, 101, 2) # Even integer from 0 to 100 inclusive
26
>>> choice(['win', 'lose', 'draw']) # Single random element from a sequence
'draw'
>>> deck = 'ace two three four'.split()
>>> shuffle(deck) # Shuffle a list
>>> deck
['four', 'two', 'ace', 'three']
>>> sample([10, 20, 30, 40, 50], k=4) # Four samples without replacement
[40, 10, 50, 30]
Симуляции:
>>> # Six roulette wheel spins (weighted sampling with replacement)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']
>>> # Deal 20 cards without replacement from a deck
>>> # of 52 playing cards, and determine the proportion of cards
>>> # with a ten-value: ten, jack, queen, or king.
>>> dealt = sample(['tens', 'low cards'], counts=[16, 36], k=20)
>>> dealt.count('tens') / 20
0.15
>>> # Estimate the probability of getting 5 or more heads from 7 spins
>>> # of a biased coin that settles on heads 60% of the time.
>>> def trial():
... return choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.4169
>>> # Probability of the median of 5 samples being in middle two quartiles
>>> def trial():
... return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.7958
Пример statistical bootstrapping использования выборки с заменой для оценки доверительного интервала для среднего значения выборки:
# https://www.thoughtco.com/example-of-bootstrapping-3126155
from statistics import fmean as mean
from random import choices
data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
means = sorted(mean(choices(data, k=len(data))) for i in range(100))
print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
f'interval from {means[5]:.1f} to {means[94]:.1f}')
Пример resampling permutation test для определения статистической значимости или p-value наблюдаемой разницы между эффектами лекарства и плацебо:
# Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
from statistics import fmean as mean
from random import shuffle
drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
observed_diff = mean(drug) - mean(placebo)
n = 10_000
count = 0
combined = drug + placebo
for i in range(n):
shuffle(combined)
new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
count += (new_diff >= observed_diff)
print(f'{n} label reshufflings produced only {count} instances with a difference')
print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
print(f'hypothesis that there is no difference between the drug and the placebo.')
Моделирование времени прибытия и доставки услуг для многосерверной очереди:
from heapq import heapify, heapreplace
from random import expovariate, gauss
from statistics import mean, quantiles
average_arrival_interval = 5.6
average_service_time = 15.0
stdev_service_time = 3.5
num_servers = 3
waits = []
arrival_time = 0.0
servers = [0.0] * num_servers # time when each server becomes available
heapify(servers)
for i in range(1_000_000):
arrival_time += expovariate(1.0 / average_arrival_interval)
next_server_available = servers[0]
wait = max(0.0, next_server_available - arrival_time)
waits.append(wait)
service_duration = max(0.0, gauss(average_service_time, stdev_service_time))
service_completed = arrival_time + wait + service_duration
heapreplace(servers, service_completed)
print(f'Mean wait: {mean(waits):.1f} Max wait: {max(waits):.1f}')
print('Quartiles:', [round(q, 1) for q in quantiles(waits)])
См.также
Statistics for Hackers видеоурок Jake Vanderplas по статистическому анализу с использованием всего нескольких фундаментальных понятий, включая моделирование, выборку, перемешивание и перекрестную валидацию.
Economics Simulation имитация рынка по Peter Norvig, которая показывает эффективное использование многих инструментов и распределений, предоставляемых этим модулем (гауссово, равномерное, выборочное, бетавариативное, выбор, треугольное и ранжированное).
A Concrete Introduction to Probability (using Python) учебник от Peter Norvig, охватывающий основы теории вероятности, как писать симуляции и как выполнять анализ данных с помощью Python.
Рецепты¶
По умолчанию random()
возвращает кратные 2-⁵³ в диапазоне 0.0 ≤ x < 1.0. Все такие числа равномерно распределены и точно представимы в виде плавающих чисел Python. Однако многие другие представимые плавающие числа в этом интервале не могут быть выбраны. Например, 0.05954861408025609
не является целым числом, кратным 2-⁵³.
В следующем рецепте используется другой подход. Все числа с плавающей точкой в интервале являются возможным выбором. Мантисса берется из равномерного распределения целых чисел в диапазоне 2⁵² ≤ мантисса < 2⁵³. Экспонента берется из геометрического распределения, где экспоненты меньше -53 встречаются в два раза реже, чем следующая большая экспонента.
from random import Random
from math import ldexp
class FullRandom(Random):
def random(self):
mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
exponent = -53
x = 0
while not x:
x = self.getrandbits(32)
exponent += x.bit_length() - 32
return ldexp(mantissa, exponent)
Все real valued distributions в классе будут использовать новый метод:
>>> fr = FullRandom()
>>> fr.random()
0.05954861408025609
>>> fr.expovariate(0.25)
8.87925541791544
Этот рецепт концептуально эквивалентен алгоритму, который выбирает из всех кратных 2-¹⁰⁷⁴ в диапазоне 0,0 ≤ x < 1,0. Все такие числа расположены равномерно, но большинство из них необходимо округлить до ближайшего представимого в Python плавающего числа. (Значение 2-¹⁰⁷⁴ является наименьшим положительным ненормированным числом и равно math.ulp(0.0)
).
См.также
Generating Pseudo-random Floating-Point Values статья Аллена Б. Дауни, описывающая способы генерации более мелкозернистых поплавков, чем обычно генерируются random()
.