Spec-Zone.ru › Python 3.9

random — Генерация псевдослучайных чисел

Исходный код: Lib/random.py

Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.

Для целых чисел реализовано равномерное выбор из диапазона. Для последовательностей реализовано равномерное выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без возвращения.

На вещественной оси есть функции для вычисления равномерного, нормального (гауссового), логарифмически нормального, экспоненциального, гамма и бета распределений. Для генерации распределений углов доступно распределение Винье.

Практически все функции модуля зависят от базовой функции random(), которая генерирует случайное вещественное число равномерно в полуоткрытом интервале [0.0, 1.0). Python использует генератор Мерсенна-Твистер в качестве основного. Он генерирует числа с плавающей точкой с точностью 53 бита и имеет период 219937-1. Подлежащая реализация на C быстрая и потокобезопасная. Генератор Мерсенна-Твистер — один из самых широко тестируемых генераторов псевдослучайных чисел, существующих на данный момент. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографических целей.

Функции, предоставляемые этим модулем, на самом деле являются связанными методами скрытого экземпляра класса random.Random. Вы можете создать свои собственные экземпляры Random, чтобы получить генераторы, которые не разделяют состояние.

Класс Random также можно наследовать, если вы хотите использовать другой базовый генератор собственного создания: в этом случае переопределите методы random(), seed(), getstate(), и setstate(). При необходимости новый генератор может предоставить метод getrandbits() — это позволяет randrange() производить выбор из произвольно большого диапазона.

Модуль random также предоставляет класс SystemRandom, который использует системную функцию os.urandom() для генерации случайных чисел из источников, предоставляемых операционной системой.

Предупреждение

Псевдослучайные генераторы этого модуля не должны использоваться в целях безопасности. Для использования в целях безопасности или криптографии, см. модуль secrets.

См. также

М. Мацумото и Т. Нисимура, «Генератор псевдослучайных чисел Мерсенна-Твистер: 623-мерно равнораспределенный», 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, которая использует все биты в строке семян.

Устарело начиная с версии 3.9: В будущем, seed должен быть одного из следующих типов: NoneType, int, float, str, bytes или bytearray.

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), что могло привести к немного неравномерному распределению.

random.randint(a, b)

Возвращает случайное целое число N, такое что a <= N <= b. Псевдоним для randrange(a, b+1).

random.getrandbits(k)

Возвращает неотрицательное целое число Python с k случайными битами. Этот метод предоставляется с генератором MersenneTwister, и некоторые другие генераторы также могут его предоставить как необязательную часть API. Когда доступен, getrandbits() позволяет randrange() обрабатывать произвольно большие диапазоны.

Изменено в версии 3.9: Теперь этот метод принимает ноль для k.

END_OF_DOCUMENT_MARKER

Функции для последовательностей

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[, 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 содержит повторения, каждое вхождение является возможным элементом выборки.

Повторяющиеся элементы могут быть указаны по одному или с необязательным ключевым параметром 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.9: В будущем population должна быть последовательностью. Экземпляры set больше не поддерживаются. Множество необходимо предварительно преобразовать в list или tuple, желательно в детерминированном порядке, чтобы выборка была воспроизводимой.

Вещественные распределения

Следующие функции генерируют конкретные вещественные распределения. Параметры функций названы в соответствии с соответствующими переменными в уравнении распределения, как это используется в обычной математической практике; большинство этих уравнений можно найти в любом учебнике по статистике.

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, делённому на желаемое среднее значение. Оно должно быть отличным от нуля. (Параметр назывался бы «лямбда», но это зарезервированное слово в 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 — параметр формы.

END_OF_DOCUMENT_MARKER

Генератор альтернатив

class random.Random([seed])

Класс, реализующий стандартный псевдослучайный генератор чисел, используемый модулем random.

Устарело начиная с версии 3.9: В будущем, seed должен быть одного из следующих типов: NoneType, int, float, str, bytes или bytearray.

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

Пример статистической бутстрап-методики с использованием ресэмплирования с возвращением для оценки доверительного интервала для среднего значения выборки:

# http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm
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, median, stdev

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}.  Stdev wait: {stdev(waits):.1f}.')
print(f'Median wait: {median(waits):.1f}.  Max wait: {max(waits):.1f}.')

См. также

Статистики для хакеров — видеоурок от 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).)

См. также

Генерация псевдослучайных значений с плавающей точкой — статья Allen B. Downey, описывающая способы генерации более тонких значений с плавающей точкой, чем обычно генерируются с помощью random().

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/random.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API