random — Генерация псевдослучайных чисел
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел происходит равномерный выбор из диапазона. Для последовательностей есть равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без возврата.
На вещественной прямой есть функции для вычисления равномерного, нормального (гауссовского), логнормального, отрицательного экспоненциального, гамма и бета распределений. Для генерации распределений углов доступно распределение Вон-Миса.
Практически все функции модуля зависят от базовой функции random(), которая генерирует случайное вещественное число равномерно в полуоткрытом интервале 0.0 <= X < 1.0. Python использует Mersenne Twister в качестве основного генератора. Он производит числа с плавающей точкой с точностью 53 бита и имеет период 219937-1. Подлежащая реализация на C быстрая и потокобезопасна. Генератор Mersenne Twister является одним из наиболее тщательно протестированных генераторов псевдослучайных чисел, существующих на данный момент. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографических целей.
Функции, предоставляемые этим модулем, фактически являются методами связанными с скрытой экземпляром класса random.Random. Вы можете создать собственные экземпляры класса Random, чтобы получить генераторы, которые не разделяют состояние.
Класс Random также может быть унаследован, если вы хотите использовать другой базовый генератор по своему выбору: для получения дополнительной информации см. документацию по этому классу.
Модуль random также предоставляет класс SystemRandom, который использует системную функцию os.urandom() для генерации случайных чисел из источников, предоставляемых операционной системой.
Предупреждение
Псевдослучайные генераторы этого модуля не должны использоваться для целей безопасности. Для целей безопасности или криптографии см. модуль secrets.
См. также
М. Мацумото и Т. Нисимура, «Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator», ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, январь, стр. 3–30, 1998.
Рецепт дополнительного умножения с переносом для совместимого альтернативного генератора псевдослучайных чисел с большим периодом и относительно простыми операциями обновления.
Примечание
Глобальный генератор случайных чисел и экземпляры класса Random потокобезопасны. Однако в свободно-потоковом построении одновременные вызовы глобального генератора или того же экземпляра Random могут столкнуться с конфликтами и плохой производительностью. Вместо этого рекомендуется использовать отдельные экземпляры класса Random на каждый поток.
Функции учета
-
random.seed(a=None, version=2) -
Инициализирует генератор случайных чисел.
Если a опущено или
None, используется текущее системное время. Если источники случайности предоставляются операционной системой, они используются вместо системного времени (см. функциюos.urandom()для получения подробной информации о доступности).Если a является целым числом, оно используется непосредственно.
В версии 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().Не следует использовать ключевые аргументы, потому что они могут интерпретироваться неожиданным образом. Например,
randrange(start=100)интерпретируется какrandrange(0, 100, 1).Изменено в версии 3.2:
randrange()более совершенен в отношении производства равномерно распределённых значений. Раньше он использовал стиль, подобныйint(random()*n), что могло приводить к немного неравномерным распределениям.Изменено в версии 3.12: Автоматическое преобразование типов, не являющихся целыми числами, больше не поддерживается. Вызовы, такие как
randrange(10.0)иrandrange(Fraction(10, 1))теперь вызывают исключение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, содержащий элементы, выбранные из population с заменой. Если population пуста, генерирует исключение
IndexError.Если задана последовательность weights, выбор осуществляется с учётом относительных весов. В противном случае, если задана последовательность cum_weights, выбор осуществляется с учётом кумулятивных весов (возможно, вычисленных с помощью
itertools.accumulate()). Например, относительные веса[10, 5, 30, 5]эквивалентны кумулятивным весам[10, 15, 45, 50]. Внутри, относительные веса преобразуются в кумулятивные перед выбором, поэтому предоставление кумулятивных весов экономит вычисления.Если ни weights, ни cum_weights не указаны, выбор осуществляется с равной вероятностью. Если указана последовательность weights, она должна иметь такую же длину, как и последовательность population. Указание weights и cum_weights одновременно является
TypeError.Weights или cum_weights могут использовать любой числовой тип, взаимодействующий со значениями
float, возвращаемыми функциейrandom()(включая целые числа, числа с плавающей точкой и дроби, но не включая десятичные числа). Веса предполагаются неотрицательными и конечными. Если все веса равны нулю, генерируется исключениеValueError.Для заданного значения seed функция
choices()с равномерным распределением весов обычно генерирует другую последовательность, чем повторные вызовы функцииchoice(). Алгоритм, используемый функциейchoices(), использует арифметику с плавающей точкой для внутренней согласованности и скорости. Алгоритм, используемый функциейchoice(), по умолчанию использует целочисленную арифметику с повторными выборами, чтобы избежать небольших искажений из-за ошибок округления.Добавлена в версии 3.6.
Изменено в версии 3.9: Генерирует исключение
ValueError, если все веса равны нулю.
-
random.shuffle(x) -
Перемешивает последовательность x на месте.
Для перемешивания неизменяемой последовательности и возврата нового перемешанного списка используйте
sample(x, k=len(x)).Обратите внимание, что даже для небольших
len(x), общее количество перестановок x может быстро превысить период большинства генераторов случайных чисел. Это означает, что большинство перестановок длинной последовательности никогда не могут быть сгенерированы. Например, последовательность длиной 2080 является самой большой, которая может уместиться в период генератора случайных чисел Мерсенна Твистер.Изменено в версии 3.11: Удален необязательный параметр random.
-
random.sample(population, k, *, counts=None) -
Возвращает список длины k, содержащий уникальные элементы, выбранные из последовательности population. Используется для случайного отбора без возвращения.
Возвращает новый список, содержащий элементы из population, не изменяя исходную последовательность. Результирующий список отсортирован по порядку выбора, поэтому все подсрезки также будут являться допустимыми случайными выборками. Это позволяет разделить победителей розыгрыша (выборка) на победителей главного приза и призёров второго места (подсрезки).
Элементы population не обязательно должны быть хешируемыми или уникальными. Если последовательность population содержит повторения, то каждое вхождение является возможным элементом выборки.
Повторные элементы могут быть указаны по одному или с использованием необязательного ключевого параметра counts. Например,
sample(['red', 'blue'], counts=[4, 2], k=5)эквивалентноsample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5).Для выбора выборки из диапазона целых чисел используйте объект
range()в качестве аргумента. Это особенно быстро и эффективно с точки зрения памяти для выборки из большой population:sample(range(10000000), k=60).Если размер выборки больше, чем размер population, генерируется исключение
ValueError.Изменено в версии 3.9: Добавлен параметр counts.
Изменено в версии 3.11: population должно быть последовательностью. Автоматическое преобразование множеств в списки больше не поддерживается.
Дискретные распределения
Следующая функция генерирует дискретное распределение.
-
random.binomialvariate(n=1, p=0.5) -
Биномиальное распределение. Возвращает количество успехов для n независимых испытаний с вероятностью успеха в каждом испытании, равной p:
Математически эквивалентно:
sum(random() < p for i in range(n))
Количество испытаний n должно быть неотрицательным целым числом. Вероятность успеха p должна быть между
0.0 <= p <= 1.0. Результатом является целое число в диапазоне0 <= X <= n.Добавлена в версии 3.12.
Вещественные распределения
Следующие функции генерируют определённые вещественные распределения. Параметры функций названы так же, как соответствующие переменные в уравнении распределения, используемые в стандартной математической практике; большинство этих уравнений можно найти в любом учебнике по статистике.
-
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и с заданным mode между этими границами. Границы low и high по умолчанию равны нулю и единице. Аргумент mode по умолчанию равен середине между границами, что даёт симметричное распределение.
-
random.betavariate(alpha, beta) -
Распределение Бета. Условия на параметры
alpha > 0иbeta > 0. Возвращаемые значения находятся в диапазоне от 0 до 1.
-
random.expovariate(lambd=1.0) -
Экспоненциальное распределение. lambd — это 1,0, делённое на желаемое среднее значение. Оно должно быть ненулевым. (Параметр назывался бы «лямбда», но это зарезервированное слово в Python.) Возвращаемые значения варьируются от 0 до положительной бесконечности, если lambd положительно, и от минус бесконечности до 0, если lambd отрицательно.
Изменено в версии 3.12: Добавлено значение по умолчанию для
lambd.
-
random.gammavariate(alpha, beta) -
Гамма-распределение. (Не гамма-функция!) Параметры формы и масштаба, 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 — среднее значение, а sigma — стандартное отклонение. Это немного быстрее, чем функция
normalvariate(), определённая ниже.Примечание по многопоточности: Когда две потоки одновременно вызывают эту функцию, возможно, что они получат одно и то же возвращаемое значение. Это можно избежать тремя способами. 1) Пусть каждый поток использует другой экземпляр генератора случайных чисел. 2) Поместите блокировки вокруг всех вызовов. 3) Используйте более медленную, но безопасную для потоков функцию
normalvariate()вместо неё.Изменено в версии 3.11: mu и sigma теперь имеют значения по умолчанию.
-
random.lognormvariate(mu, sigma) -
Логарифмически нормальное распределение. Если взять натуральный логарифм этого распределения, получится нормальное распределение со средним значением mu и стандартным отклонением sigma. mu может иметь любое значение, а sigma должно быть больше нуля.
-
random.normalvariate(mu=0.0, sigma=1.0) -
Нормальное распределение. mu — среднее значение, а sigma — стандартное отклонение.
Изменено в версии 3.11: mu и sigma теперь имеют значения по умолчанию.
-
random.vonmisesvariate(mu, kappa) -
mu — средний угол, выраженный в радианах от 0 до 2*pi, а kappa — параметр концентрации, который должен быть больше или равен нулю. Если kappa равно нулю, это распределение сводится к равномерному случайному углу в диапазоне от 0 до 2*pi.
-
random.paretovariate(alpha) -
Распределение Парето. alpha — параметр формы.
-
random.weibullvariate(alpha, beta) -
Распределение Вейбулла. 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, если вызываются.
Примечания по воспроизводимости
Иногда полезно иметь возможность воспроизводить последовательности, задаваемые генератором псевдослучайных чисел. Используя значение seed, та же последовательность должна воспроизводиться от запуска к запуску, пока не работает несколько потоков.
Большинство алгоритмов и функций инициализации модуля random могут изменяться между версиями Python, но два аспекта гарантированно не изменятся:
- Если добавляется новый метод инициализации, то будет предложен обратный совместимый инициализатор.
- Метод генератора
random()будет продолжать генерировать ту же последовательность, когда совместимый инициализатор получает тот же seed.
Примеры
Основные примеры:
>>> 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.
>>> deal = sample(['tens', 'low cards'], counts=[16, 36], k=20)
>>> deal.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.
>>> sum(binomialvariate(n=7, p=0.6) >= 5 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
Пример статистического бутстрапа с использованием ресемплирования с возвращением для оценки доверительного интервала для среднего значения выборки:
# 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}')
Пример перестановочного теста ресемплирования, чтобы определить статистическую значимость или p-значение наблюдаемого различия между эффектами лекарства и плацебо:
# 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)])
См. также
Статистика для хакеров — обучающее видео от Джейка Вандерпласа по статистическому анализу с использованием лишь нескольких фундаментальных концепций, включая моделирование, выборку, перемешивание и перекрестную проверку.
Моделирование экономики — моделирование рынка от Питера Норвига, демонстрирующее эффективное использование многих инструментов и распределений, предоставляемых данным модулем (gauss, uniform, sample, betavariate, choice, triangular и randrange).
Конкретное введение в теорию вероятностей (с использованием Python) — учебное пособие от Питера Норвига, охватывающее основы теории вероятностей, как писать моделирования и как выполнять анализ данных с использованием 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⁻⁵³ в диапазоне 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)
Все распределения вещественных чисел в классе будут использовать новый метод:
>>> fr = FullRandom() >>> fr.random() 0.05954861408025609 >>> fr.expovariate(0.25) 8.87925541791544
Этот рецепт концептуально эквивалентен алгоритму, который выбирает из всех кратных 2⁻¹⁰⁷⁴ в диапазоне 0.0 ≤ x < 1.0. Все такие числа равномерно распределены, но большинство из них необходимо округлить до ближайшего представимого числа с плавающей точкой Python. (Значение 2⁻¹⁰⁷⁴ — наименьшее положительное ненормализованное число с плавающей точкой и равно math.ulp(0.0).)
См. также
Генерация псевдослучайных значений с плавающей точкой — статья Аллена Б. Дауни, описывающая способы генерации чисел с плавающей точкой с более высокой точностью, чем обычно генерирует random().
Использование в командной строке
Добавлен в версии 3.13.
Модуль random может быть выполнен из командной строки.
python -m random [-h] [-c CHOICE [CHOICE ...] | -i N | -f N] [input ...]
Принимаются следующие параметры:
-
-h, --help -
Показать сообщение справки и выйти.
-
-c CHOICE [CHOICE ...] -
--choice CHOICE [CHOICE ...] -
Вывести случайный выбор, используя
choice().
-
-i <N> -
--integer <N> -
Вывести случайное целое число от 1 до N включительно, используя
randint().
-
-f <N> -
--float <N> -
Вывести случайное число с плавающей точкой от 0 до N включительно, используя
uniform().
Если не указаны параметры, вывод зависит от входных данных:
Пример использования в командной строке
Вот несколько примеров использования интерфейса командной строки модуля random:
$ # Choose one at random $ python -m random egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce" Lobster Thermidor aux crevettes with a Mornay sauce $ # Random integer $ python -m random 6 6 $ # Random floating-point number $ python -m random 1.8 1.7080016272295635 $ # With explicit arguments $ python -m random --choice egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce" egg $ python -m random --integer 6 3 $ python -m random --float 1.8 1.5666339105010318 $ python -m random --integer 6 5 $ python -m random --float 6 3.1942323316565915
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/random.html