random
— Генерация псевдослучайных чисел¶
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел предусмотрен равномерный выбор из диапазона. Для последовательностей предусмотрен равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без замены.
На реальной прямой имеются функции для вычисления равномерного, нормального (гауссова), логнормального, отрицательного экспоненциального, гамма- и бета-распределений. Для генерации распределений углов доступно распределение фон Мизеса.
Почти все функции модуля зависят от базовой функции random()
, которая равномерно генерирует случайное число с плавающей точкой в полуоткрытом диапазоне 0.0 <= X < 1.0
. Python использует Mersenne Twister в качестве основного генератора. Он генерирует числа с плавающей запятой с точностью до 53 бит и имеет период 2**19937-1. Базовая реализация на C является быстрой и потокобезопасной. Mersenne Twister - один из наиболее тщательно протестированных генераторов случайных чисел из существующих. Однако, будучи полностью детерминированным, он подходит не для всех целей и совершенно не подходит для криптографических целей.
Функции, предоставляемые этим модулем, на самом деле являются связанными методами скрытого экземпляра класса random.Random
. Вы можете создать свои собственные экземпляры класса Random
, чтобы получить генераторы, которые не разделяют состояние.
Класс Random
также может быть разделен на подклассы, если вы хотите использовать другой базовый генератор собственной разработки: более подробную информацию смотрите в документации по этому классу.
Модуль random
также предоставляет класс SystemRandom
, который использует системную функцию os.urandom()
для генерации случайных чисел из источников, предоставляемых операционной системой.
Предупреждение
Псевдослучайные генераторы этого модуля не должны использоваться в целях безопасности. Для обеспечения безопасности или криптографического использования смотрите модуль secrets
.
См.также
М. Мацумото и Т. Нисимура, «Смерч Мерсенна: генератор равномерно распределенных псевдослучайных чисел в 623 измерениях», ACM Transactions on Modeling and Computer Simulation, том 8, № 1, стр.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)¶
состояние должно было быть получено в результате предыдущего вызова
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.Шаблон позиционных аргументов совпадает с шаблоном
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 случайными битами. Этот метод поставляется с генератором Mersenne Twister, и некоторые другие генераторы также могут предоставлять его как необязательную часть API. Если доступно,
getrandbits()
позволяетrandrange()
обрабатывать произвольно большие диапазоны.Изменено в версии 3.9: Этот метод теперь принимает ноль для k.
Функции для последовательностей¶
- random.choice(seq)¶
Возвращает случайный элемент из непустой последовательности seq. Если seq пуст, то выводится значение
IndexError
.
- random.choices(population, weights=None, *, cum_weights=None, k=1)¶
Возвращает список элементов размером с k, выбранных из совокупности, с заменой. Если совокупность пуста, выводится значение
IndexError
.Если задана последовательность весов, выбор производится в соответствии с относительными весами. В качестве альтернативы, если задана последовательность суммарных весов, выбор производится в соответствии с суммарными весами (возможно, вычисленными с использованием
itertools.accumulate()
). Например, относительные веса[10, 5, 30, 5]
эквивалентны суммарным весам[10, 15, 45, 50]
. Перед выполнением выбора относительные веса преобразуются в суммарные веса, поэтому ввод суммарных весов экономит время.Если не указаны ни weights, ни cum_weights, выбор производится с равной вероятностью. Если указана последовательность весов, она должна быть той же длины, что и последовательность population. Это
TypeError
для указания как weights, так и cum_weights.В weights или cum_weights может использоваться любой числовой тип, который взаимодействует со значениями
float
, возвращаемымиrandom()
(включая целые числа, числа с плавающей точкой и дроби, но исключая десятичные). Предполагается, что значения весов неотрицательны и конечны. ЗначениеValueError
увеличивается, если все значения весов равны нулю.Для данного начального значения функция
choices()
с равным весом обычно выдает последовательность, отличную от повторных вызововchoice()
. Алгоритм, используемыйchoices()
, использует арифметику с плавающей запятой для обеспечения внутренней согласованности и скорости. Алгоритм, используемыйchoice()
, по умолчанию использует целочисленную арифметику с повторяющимися выборками, чтобы избежать небольших погрешностей из-за ошибки округления.Добавлено в версии 3.6.
Изменено в версии 3.9: Выдает значение
ValueError
, если все веса равны нулю.
- random.shuffle(x)¶
Перемешайте последовательность x на месте.
Чтобы перетасовать неизменяемую последовательность и вернуть новый перетасованный список, используйте вместо этого
sample(x, k=len(x))
.Обратите внимание, что даже при малом
len(x)
общее число перестановок x может быстро превысить период действия большинства генераторов случайных чисел. Это означает, что большинство перестановок длинной последовательности никогда не могут быть сгенерированы. Например, последовательность длиной 2080 является наибольшей, которая может поместиться в период генератора случайных чисел Mersenne Twister.Изменено в версии 3.11: Удален необязательный параметр random.
- random.sample(population, k, *, counts=None)¶
Возвращает список уникальных элементов, выбранных из генеральной совокупности. Используется для случайной выборки без замены.
Возвращает новый список, содержащий элементы из совокупности, при этом исходная совокупность остается неизменной. Результирующий список составлен в порядке выборки, так что все подслои также будут действительными случайными выборками. Это позволяет разделить победителей розыгрыша (выборка) на обладателей главного приза и вторых мест (подразделы).
Члены совокупности не обязательно должны быть 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.
Изменено в версии 3.11: Совокупность должна быть последовательностью. Автоматическое преобразование наборов в списки больше не поддерживается.
Вещественнозначные распределения¶
Приведенные ниже функции генерируют конкретные действительные распределения. Параметры функции названы в честь соответствующих переменных в уравнении распределения, как это используется в обычной математической практике; большинство этих уравнений можно найти в любом тексте по статистике.
- random.random()¶
Возвращает следующее случайное число с плавающей запятой в диапазоне
0.0 <= X < 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, деленному на желаемое среднее значение. Оно должно быть отличным от нуля. (Параметр можно было бы назвать «lambda», но в Python это зарезервированное слово.) Возвращаемые значения варьируются от 0 до положительной бесконечности, если lambd является положительным, и от отрицательной бесконечности до 0, если lambd является отрицательным.
- random.gammavariate(alpha, beta)¶
Гамма-распределение. (Не функция гамма!) Параметры формы и масштаба, альфа и бета, должны иметь положительные значения. (Соглашения о вызовах различаются, и в некоторых источниках «бета» определяется как величина, обратная масштабу).
Функция распределения вероятностей равна:
x ** (alpha - 1) * math.exp(-x / beta) pdf(x) = -------------------------------------- math.gamma(alpha) * beta ** alpha
- random.gauss(mu=0.0, sigma=1.0)¶
Нормальное распределение, также называемое гауссовым распределением. mu - среднее значение, а сигма - стандартное отклонение. Это немного быстрее, чем функция
normalvariate()
, определенная ниже.Многопоточность примечание: Когда два потока одновременно вызывают эту функцию, возможно, что они получат одно и то же возвращаемое значение. Этого можно избежать тремя способами. 1) Пусть каждый поток использует другой экземпляр генератора случайных чисел. 2) Заблокируйте все вызовы. 3) Вместо этого используйте более медленную, но потокобезопасную функцию
normalvariate()
.Изменено в версии 3.11: mu и sigma теперь имеют аргументы по умолчанию.
- random.lognormvariate(mu, sigma)¶
Логарифмически нормальное распределение. Если вы возьмете натуральный логарифм этого распределения, то получите нормальное распределение со средним значением mu и стандартным отклонением сигма. mu может иметь любое значение, а сигма должна быть больше нуля.
- random.normalvariate(mu=0.0, sigma=1.0)¶
Нормальное распределение. mu - среднее значение, а сигма - стандартное отклонение.
Изменено в версии 3.11: mu и sigma теперь имеют аргументы по умолчанию.
- random.vonmisesvariate(mu, kappa)¶
mu - это средний угол, выраженный в радианах от 0 до 2**pi*, а kappa - параметр концентрации, который должен быть больше или равен нулю. Если kappa равно нулю, то это распределение сводится к равномерному случайному углу в диапазоне от 0 до 2**pi*.
- random.paretovariate(alpha)¶
Распределение Парето. альфа - параметр формы.
- random.weibullvariate(alpha, beta)¶
Распределение Вейбулла. альфа - параметр масштаба, а бета - параметр формы.
Альтернативный генератор¶
- class random.Random([seed])¶
Класс, реализующий генератор псевдослучайных чисел по умолчанию, используемый модулем
random
.Изменено в версии 3.11: Раньше seed мог быть любым хэшируемым объектом. Теперь он ограничен значением:
None
,int
,float
,str
,bytes
, илиbytearray
.Подклассы
Random
должны переопределять следующие методы, если они хотят использовать другой базовый генератор:- seed(a=None, version=2)¶
Переопределите этот метод в подклассах, чтобы настроить поведение
seed()
экземпляровRandom
.
- getstate()¶
Переопределите этот метод в подклассах, чтобы настроить поведение
getstate()
экземпляровRandom
.
- setstate(state)¶
Переопределите этот метод в подклассах, чтобы настроить поведение
setstate()
экземпляровRandom
.
- random()¶
Переопределите этот метод в подклассах, чтобы настроить поведение
random()
экземпляровRandom
.
Необязательно, пользовательский подкласс генератора также может предоставлять следующий метод:
- getrandbits(k)¶
Переопределите этот метод в подклассах, чтобы настроить поведение
getrandbits()
экземпляров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, которое демонстрирует эффективное использование многих инструментов и распределений, предоставляемых этим модулем (gauss, uniform, sample, betavariate, choice, triangular и randrange).
A Concrete Introduction to Probability (using Python) учебное пособие от Peter Norvig, посвященное основам теории вероятностей, написанию симуляций и проведению анализа данных с помощью Python.
Рецепты¶
Эти рецепты показывают, как эффективно делать случайные выборки с помощью итераторов комбинаторики в модуле itertools
:
def random_product(*args, repeat=1):
"Random selection from itertools.product(*args, **kwds)"
pools = [tuple(pool) for pool in args] * repeat
return tuple(map(random.choice, pools))
def random_permutation(iterable, r=None):
"Random selection from itertools.permutations(iterable, r)"
pool = tuple(iterable)
r = len(pool) if r is None else r
return tuple(random.sample(pool, r))
def random_combination(iterable, r):
"Random selection from itertools.combinations(iterable, r)"
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.sample(range(n), r))
return tuple(pool[i] for i in indices)
def random_combination_with_replacement(iterable, r):
"Choose r elements with replacement. Order the result to match the iterable."
# Result will be in set(itertools.combinations_with_replacement(iterable, r)).
pool = tuple(iterable)
n = len(pool)
indices = sorted(random.choices(range(n), k=r))
return tuple(pool[i] for i in indices)
Значение по умолчанию random()
возвращает значения, кратные 2⁻⁵3 в диапазоне 0.0 ≤ x < 1.0. Все такие числа расположены на равном расстоянии друг от друга и в точности представимы в виде чисел с плавающей запятой в Python. Однако многие другие представимые значения с плавающей точкой в этом интервале не являются возможными выборками. Например, 0.05954861408025609
не является целым числом, кратным 2⁻⁵3.
В следующем рецепте используется другой подход. Все числа с плавающей точкой в интервале являются возможными выборками. Мантисса получается из равномерного распределения целых чисел в диапазоне 2⁵2 ≤ мантисса < 2⁵3. Показатель степени определяется геометрическим распределением, в котором показатели, меньшие -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⁻1⁰⁷⁴, в диапазоне 0.0 ≤ x < 1.0. Все такие числа расположены равномерно, но большинство из них необходимо округлить в меньшую сторону до ближайшего числа с плавающей точкой, которое может быть представлено в Python. (Значение 2⁻1⁰⁷⁴ является наименьшим положительным ненормализованным значением с плавающей точкой и равно math.ulp(0.0)
.)
См.также
Generating Pseudo-random Floating-Point Values статья Аллена Б. Дауни, описывающая способы генерации более мелкозернистых чисел с плавающей запятой, чем обычно генерируется с помощью random()
.