random — Генерация псевдослучайных чисел
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел выполняется равномерный выбор из диапазона. Для последовательностей выполняется равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без повторений.
На вещественной оси есть функции для вычисления равномерного, нормального (гауссового), логарифмически-нормального, отрицательно-экспоненциального, гамма- и бета-распределений. Для генерации распределений углов доступно распределение Винера.
Практически все функции модуля зависят от базовой функции random(), которая генерирует случайное вещественное число равномерно в полуоткрытом диапазоне 0.0 <= X < 1.0. Python использует метод Мерсенна-Твистера в качестве основного генератора. Он производит числа с плавающей запятой с точностью 53 бита и имеет период 219937-1. Базовая реализация на C является быстрой и потокобезопасной. Генератор Мерсенна-Твистер является одним из наиболее широко проверенных генераторов псевдослучайных чисел. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографических целей.
Функции, предоставляемые этим модулем, фактически являются связанными методами скрытого экземпляра класса random.Random. Вы можете создать свои экземпляры класса Random, чтобы получить генераторы, которые не разделяют состояние.
Класс Random также может быть унаследован, если вы хотите использовать другой базовый генератор по своему усмотрению: см. документацию по этому классу для получения дополнительной информации.
Модуль random также предоставляет класс SystemRandom, который использует системную функцию os.urandom() для генерации случайных чисел из источников, предоставляемых операционной системой.
Предупреждение
Генераторы псевдослучайных чисел этого модуля не должны использоваться в целях безопасности. Для использования в целях безопасности или криптографии, см. модуль secrets.
См. также
М. Мацумото и Т. Нисимура, «Генератор псевдослучайных чисел Мерсенна-Твистер: 623-мерно равнораспределённый равномерный генератор», ACM Transactions on Modeling and Computer Simulation, том 8, № 1, январь, стр. 3–30, 1998 г.
Рецепт «Умножение с переносом» для совместимой альтернативной генерации псевдослучайных чисел с большим периодом и относительно простыми операциями обновления.
Функции ведения учёта
-
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 случайными битами. Этот метод предоставляется генератором Мерсенна-Твистера, и некоторые другие генераторы могут также предоставлять его как необязательную часть 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 не обязательно должны быть хешируемыми или уникальными. Если 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.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) -
Экспоненциальное распределение. lambd равно 1,0, делённому на желаемое среднее значение. Оно должно быть отличным от нуля. (Параметр назывался бы «lambda», но это зарезервированное слово в Python.) Возвращаемые значения находятся в диапазоне от 0 до положительной бесконечности, если lambd положительно, и от отрицательной бесконечности до 0, если 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при вызове.
Примечания о воспроизводимости
Иногда бывает полезно иметь возможность воспроизвести последовательности, задаваемые генератором псевдослучайных чисел. Используя значение 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)])
См. также
Статистики для хакеров видео-урок Джека Вандерпласа по статистическому анализу, используя лишь несколько основных концепций, включая моделирование, выборку, перемешивание и перекрестную проверку.
Моделирование экономики симуляция рынка Питера Норвига, показывающая эффективное использование многих инструментов и распределений, предоставляемых этим модулем (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⁵² ≤ 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.11/library/random.html