random — Генерация псевдослучайных чисел
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел есть равномерный выбор из диапазона. Для последовательностей есть равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без повторений.
На вещественной оси есть функции для вычисления равномерного, нормального (гауссовского), логарифмически-нормального, отрицательного экспоненциального, гамма- и бета-распределений. Для генерации распределений углов доступно распределение фон Мизеса.
Практически все функции модуля зависят от базовой функции random(), которая генерирует случайное вещественное число равномерно в полуоткрытом интервале [0.0, 1.0). Python использует Mersenne Twister в качестве основного генератора. Он производит с плавающей точкой с 53-битной точностью и имеет период 2**19937-1. Базовая реализация на C является быстрой и потокобезопасной. Генератор Mersenne Twister — один из самых широко тестируемых генераторов псевдослучайных чисел, существующих в настоящее время. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографических целей.
Функции, предоставляемые этим модулем, фактически являются связанными методами скрытого экземпляра класса random.Random. Вы можете создать свои экземпляры класса Random, чтобы получить генераторы, которые не разделяют состояние.
Класс Random также можно наследовать, если вы хотите использовать другой базовый генератор по своему выбору: в этом случае переопределите методы random(), seed(), getstate(), и setstate(). Дополнительно, новый генератор может предоставить метод getrandbits(), что позволяет randrange() производить выбор в произвольно большом диапазоне.
Модуль random также предоставляет класс SystemRandom, который использует системную функцию os.urandom() для генерации случайных чисел из источников, предоставляемых операционной системой.
Предупреждение
Генераторы псевдослучайных чисел этого модуля не должны использоваться для целей безопасности. Для целей безопасности или криптографии см. модуль secrets.
См. также
M. Matsumoto and T. Nishimura, “Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator”, ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.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(). Не следует использовать ключевые аргументы, так как функция может использовать их непредсказуемым образом.Изменено в версии 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, содержащий элементы, выбранные из population с заменой. Если population пуста, возбуждает исключение
IndexError.Если указана последовательность weights, выборки осуществляются в соответствии с относительными весами. В противном случае, если задана последовательность cum_weights, выборки осуществляются в соответствии с накопительными весами (возможно, вычисленными с помощью
itertools.accumulate()). Например, относительные веса[10, 5, 30, 5]эквивалентны накопительным весам[10, 15, 45, 50]. Внутренне, относительные веса преобразуются в накопительные веса перед выбором элементов, поэтому предоставление накопительных весов экономит вычисления.Если ни weights, ни cum_weights не указаны, выборки делаются с равной вероятностью. Если указана последовательность весов, она должна иметь такую же длину, как и последовательность population. Указание и 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, 1.0); по умолчанию это функция
random().Чтобы перемешать неизменяемую последовательность и вернуть новый перемешанный список, используйте
sample(x, k=len(x))вместо этого.Обратите внимание, что даже для небольших
len(x), общее число перестановок x может быстро стать больше, чем период большинства генераторов случайных чисел. Это означает, что большинство перестановок длинной последовательности никогда не смогут быть сгенерированы. Например, последовательность длиной 2080 является самой большой, которая может поместиться в период генератора случайных чисел Mersenne Twister.Устарело начиная с версии 3.9, будет удалено в версии 3.11: Необязательный параметр random.
-
random.sample(population, k, *, counts=None) -
Возвращает список длиной k, содержащий уникальные элементы, выбранные из последовательности или множества population. Используется для случайной выборки без возвращения.
Возвращает новый список, содержащий элементы из population, не изменяя исходную population. Результирующий список отсортирован по порядку выбора, так что все подсрезки также будут являться корректными случайными выборками. Это позволяет разделить победителей лотереи (выборка) на победителей гран-при и призеров второго места (подсрезки).
Элементы population не обязательно должны быть хешируемыми или уникальными. Если population содержит повторения, каждое вхождение является возможным выбором в sample.
Повторяющиеся элементы можно указывать по одному или с помощью необязательного параметра 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.
Вещественные распределения
Следующие функции генерируют конкретные вещественные распределения. Параметры функций названы в соответствии с соответствующими переменными в уравнении распределения, как используются в общепринятой математической практике; большинство этих уравнений можно найти в любом учебнике по статистике.
-
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и с указанным mode между этими границами. Границы 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) -
Распределение гамма. (Не гамма-функция!) Условия для параметров —
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) -
Распределение Вейбулла. alpha — параметр масштаба, а beta — параметр формы.
Генератор альтернатив
-
class random.Random([seed]) -
Класс, реализующий стандартный псевдослучайный генератор чисел, используемый модулем
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.
>>> 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
Пример статистического бутстраппинга, использующего ресэмплирование с возвращением для оценки доверительного интервала для среднего значения выборки:
# 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)])
См. также
Статистика для хакеров, учебное видео от Jake Vanderplas по статистическому анализу, используя только несколько основных концепций, включая моделирование, выборку, перетасовку и перекрестную проверку.
Моделирование экономики, моделирование рынка от Peter Norvig, показывающее эффективное использование многих инструментов и распределений, предоставляемых этим модулем (gauss, uniform, sample, betavariate, choice, triangular и randrange).
Конкретное введение в теорию вероятности (с использованием Python), учебное пособие от Peter Norvig, охватывающее основы теории вероятности, как писать моделирования и как выполнять анализ данных с помощью Python.
Рецепты
По умолчанию random() возвращает кратные 2⁻⁵³ в диапазоне 0.0 ≤ x < 1.0. Все такие числа равномерно распределены и точно представляются как числа с плавающей запятой Python. Однако многие другие представимые числа с плавающей запятой в этом интервале не могут быть выбраны. Например, 0.05954861408025609 не является целым кратным 2⁻⁵³.
Следующий рецепт использует другой подход. Все числа с плавающей запятой в интервале могут быть выбраны. Мантисса берется из равномерного распределения целых чисел в диапазоне 2⁵² ≤ mantissa < 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/random.html