random — Генерация псевдослучайных чисел
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел существует равномерный выбор из диапазона. Для последовательностей существует равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без повторения.
На вещественной оси есть функции для вычисления равномерного, нормального (гауссова), логарифмически нормального, отрицательно экспоненциального, гамма и бета распределений. Для генерации распределений углов доступно распределение Винера.
Практически все функции модуля зависят от основной функции random(), которая генерирует случайное вещественное число равномерно в полуоткрытом интервале 0.0 <= X < 1.0. Python использует генератор Мерсенна-Твистера в качестве основного. Он генерирует числа с точностью 53 бита и имеет период 219937-1. Подлежащая реализация на C одновременно быстрая и потокобезопасная. Генератор Мерсенна-Твистера является одним из наиболее широко протестированных генераторов псевдослучайных чисел, существующих на данный момент. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографических целей.
Функции, предоставляемые этим модулем, фактически являются связанными методами скрытого экземпляра класса random.Random. Вы можете создать собственные экземпляры Random, чтобы получить генераторы, которые не разделяют состояние.
Класс Random также может быть расширен, если вы хотите использовать другой базовый генератор по собственному замыслу: см. документацию по этому классу для получения дополнительной информации.
Модуль random также предоставляет класс SystemRandom, который использует системную функцию os.urandom() для генерации случайных чисел из источников, предоставленных операционной системой.
Предупреждение
Псевдослучайные генераторы этого модуля не должны использоваться для целей безопасности. Для целей безопасности или криптографии см. модуль secrets.
См. также
M. Matsumoto и T. Nishimura, «Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator», ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, январь с. 3–30 1998.
Рецепт Complementary-Multiply-with-Carry для совместимого альтернативного генератора псевдослучайных чисел с большим периодом и относительно простыми операциями обновления.
Функции учета
-
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 случайными битами. Этот метод поставляется с генератором Мерсенна-Твистера, и некоторые другие генераторы также могут предоставить его в качестве необязательной части 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.Для заданного зерна функция
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) -
Возвращает список из 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, делённому на желаемое среднее значение. Оно должно быть ненулевым. (Параметр был бы назван «lambda», но это зарезервированное слово в Python.) Возвращаемые значения колеблются от 0 до положительной бесконечности, если lambd положительно, и от отрицательной бесконечности до 0, если lambd отрицательно.
Изменено в версии 3.12: Добавлено значение по умолчанию для
lambd.
-
random.gammavariate(alpha, beta) -
Гамма-распределение. (Не гамма-функция!) Параметры формы и масштаба, alpha и beta, должны иметь положительные значения. (Конвенции вызова различаются, и в некоторых источниках «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, если вызваны.
Примечания о воспроизводимости
Иногда бывает полезно иметь возможность воспроизводить последовательности, задаваемые генератором псевдослучайных чисел. Повторное использование значения семени должно обеспечивать воспроизводимость последовательности при каждом запуске, пока не будут работать несколько потоков.
Большинство алгоритмов и функций инициализации семян модуля 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.
>>> 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().
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/random.html