Содержание страницы
9.6. random – Генерация псевдослучайных чисел¶random – Generate pseudo-random numbers
Исходный код: Lib/random.py
Этот модуль реализует генераторы псевдослучайных чисел для различных распределений.
Для целых чисел есть равномерный выбор из диапазона. Для последовательностей есть равномерный выбор случайного элемента, функция для генерации случайной перестановки списка на месте и функция для случайной выборки без возвращения.
На вещественной прямой есть функции для вычисления равномерного, нормального (гауссовского), логнормального, отрицательного экспоненциального, гамма и бета распределений. Для генерации распределений углов доступно распределение фон Мизеса.
Почти все функции модуля зависят от базовой функции random(), которая генерирует случайное число с плавающей запятой, равномерно распределённое в полуоткрытом диапазоне [0.0, 1.0). Python использует вихрь Мерсенна в качестве основного генератора. Он выдаёт числа с плавающей запятой точностью 53 бита и имеет период 2**19937-1. Базовая реализация на C быстра и потокобезопасна. Вихрь Мерсенна – один из наиболее тщательно протестированных генераторов случайных чисел. Однако, будучи полностью детерминированным, он не подходит для всех целей и совершенно непригоден для криптографии.
Функции, предоставляемые этим модулем, на самом деле являются привязанными методами скрытого
экземпляра класса random.Random. Можно создать собственные
экземпляры Random, чтобы получить генераторы, не разделяющие состояние.
Класс Random также можно наследовать, если требуется использовать другой базовый генератор собственной разработки: в этом случае необходимо переопределить методы random(), seed(), getstate() и setstate(). При необходимости новый генератор может предоставить метод getrandbits() – это позволяет randrange() производить выборки из произвольно большого диапазона.
Модуль random также предоставляет класс SystemRandom, который
использует системную функцию os.urandom() для генерации случайных чисел
из источников, предоставляемых операционной системой.
Предупреждение
Псевдослучайные генераторы этого модуля не следует использовать для
целей безопасности. Для безопасности или криптографического использования см. модуль
secrets.
См. также
М. Мацумото и Т. Нисимура, «Вихрь Мерсенна: 623-мерно равномерно распределенный генератор псевдослучайных чисел», ACM Transactions on Modeling and Computer Simulation том 8, № 1, январь, стр. 3–30, 1998.
Complementary-Multiply-with-Carry recipe для совместимого альтернативного генератора случайных чисел с длинным периодом и сравнительно простыми операциями обновления.
9.6.1. Служебные функции¶Bookkeeping functions
-
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.getrandbits(k)¶ Возвращает целое число Python с k случайными битами. Этот метод предоставляется генератором MersenneTwister; некоторые другие генераторы также могут предоставлять его как опциональную часть API. Если доступен,
getrandbits()позволяетrandrange()работать с произвольно большими диапазонами.
9.6.2. Функции для целых чисел¶Functions for integers
-
random.randrange(stop)¶ -
random.randrange(start, stop[, step]) Возвращает случайно выбранный элемент из
range(start, stop, step). Это равнозначноchoice(range(start, stop, step)), но на самом деле не создаёт объект range.Шаблон позиционных аргументов совпадает с шаблоном
range(). Именованные аргументы не следует использовать, поскольку функция может применить их неожиданным образом.Изменено в версии 3.2:
randrange()стала более совершенной в генерации равномерно распределённых значений. Ранее использовался подход, подобныйint(random()*n), который мог давать несколько неравномерные распределения.
-
random.randint(a, b)¶ Возвращает случайное целое N такое, что
a <= N <= b. Псевдоним дляrandrange(a, b+1).
9.6.3. Функции для последовательностей¶Functions for sequences
-
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()(сюда входят целые числа, числа с плавающей точкой и дроби, но не десятичные).Новое в версии 3.6.
-
random.shuffle(x[, random])¶ Перемешивает последовательность x на месте.
Необязательный аргумент random – это функция без аргументов, возвращающая случайное число с плавающей запятой из диапазона [0.0, 1.0); по умолчанию это функция
random().Чтобы перемешать неизменяемую последовательность и вернуть новый перемешанный список, используйте
sample(x, k=len(x)).Обратите внимание, что даже для небольших
len(x)общее число перестановок x может быстро превысить период большинства генераторов случайных чисел. Это означает, что большинство перестановок длинной последовательности никогда не могут быть сгенерированы. Например, последовательность длины 2080 – это самая длинная, которая умещается в период генератора случайных чисел Mersenne Twister.
-
random.sample(population, k)¶ Возвращает список длины k из уникальных элементов, выбранных из последовательности population или множества. Используется для случайной выборки без возвращения.
Возвращает новый список, содержащий элементы из population, не изменяя исходную population. Результирующий список упорядочен по порядку выбора, так что все подсписки также будут корректными случайными выборками. Это позволяет разделить победителей розыгрыша (выборку) на обладателей главного и второго призов (подсписки).
Элементы population не обязаны быть хэшируемыми или уникальными. Если population содержит повторения, то каждое вхождение является возможным элементом выборки.
Чтобы выбрать выборку из диапазона целых чисел, используйте объект
range()в качестве аргумента. Это особенно быстро и эффективно по памяти при выборке из большой популяции:sample(range(10000000), k=60).Если размер выборки превышает размер популяции, возбуждается исключение
ValueError.
9.6.4. Непрерывные распределения¶Real-valued distributions
Следующие функции генерируют конкретные вещественные распределения. Имена параметров функций соответствуют переменным в уравнении распределения, как принято в математической практике; большинство этих уравнений можно найти в любом учебнике по статистике.
-
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и с заданной модой между этими границами. Границы 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(), определённая ниже.
-
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 – параметр формы.
9.6.5. Альтернативный генератор¶Alternative Generator
-
class
random.SystemRandom([seed])¶ Класс, использующий функцию
os.urandom()для генерации случайных чисел из источников, предоставляемых операционной системой. Доступен не на всех системах. Не зависит от состояния программного обеспечения, и последовательности невоспроизводимы. Соответственно, методseed()не действует и игнорируется. Методыgetstate()иsetstate()вызываютNotImplementedErrorпри вызове.
9.6.6. Замечания по воспроизводимости¶Notes on Reproducibility
Иногда бывает полезно воспроизводить последовательности, выдаваемые генератором псевдослучайных чисел. При повторном использовании одного и того же начального значения (seed) одна и та же последовательность должна воспроизводиться от запуска к запуску, если не запущено несколько потоков.
Большинство алгоритмов и функций инициализации генератора модуля random могут меняться в разных версиях Python, но два аспекта гарантированно остаются неизменными:
Если будет добавлен новый метод инициализации, будет предложен обратно совместимый инициализатор.
Метод
random()генератора продолжит выдавать ту же последовательность, если совместимому инициализатору передать то же начальное значение.
9.6.7. Примеры и рецепты¶Examples and Recipes
Простые примеры:
>>> random() # Случайное число с плавающей точкой: 0.0 <= x < 1.0
0.37444887175646646
>>> uniform(2.5, 10.0) # Случайное число с плавающей точкой: 2.5 <= x < 10.0
3.1800146073117523
>>> expovariate(1 / 5) # Интервал между поступлениями в среднем 5 секунд
5.148957571865031
>>> randrange(10) # Целое число от 0 до 9 включительно
7
>>> randrange(0, 101, 2) # Чётное целое число от 0 до 100 включительно
26
>>> choice(['win', 'lose', 'draw']) # Один случайный элемент из последовательности
'draw'
>>> deck = 'ace two three four'.split()
>>> shuffle(deck) # Перемешать список
>>> deck
['four', 'two', 'ace', 'three']
>>> sample([10, 20, 30, 40, 50], k=4) # Четыре выборки без возвращения
[40, 10, 50, 30]
Симуляции:
>>> # Шесть вращений колеса рулетки (взвешенная выборка с возвращением)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']
>>> # Раздать 20 карт без возврата из колоды в 52 игральные карты
>>> # и определить долю карт с номиналом десять
>>> # (десятка, валет, дама или король).
>>> deck = collections.Counter(tens=16, low_cards=36)
>>> seen = sample(list(deck.elements()), k=20)
>>> seen.count('tens') / 20
0.15
>>> # Оценить вероятность выпадения 5 или более орлов за 7 подбрасываний
>>> # несимметричной монеты, которая выпадает орлом в 60% случаев.
>>> trial = lambda: choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
>>> sum(trial() for i in range(10000)) / 10000
0.4169
>>> # Вероятность того, что медиана 5 выборок окажется в двух средних квартилях
>>> trial = lambda : 2500 <= sorted(choices(range(10000), k=5))[2] < 7500
>>> sum(trial() for i in range(10000)) / 10000
0.7958
Пример статистического бутстрэпа с использованием повторной выборки с возвращением для оценки доверительного интервала среднего выборки размером пять:
# http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm
from statistics import mean
from random import choices
data = 1, 2, 4, 4, 10
means = sorted(mean(choices(data, k=5)) for i in range(20))
print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
f'interval from {means[1]:.1f} to {means[-2]:.1f}')
Пример пермутационного теста с повторной выборкой для определения статистической значимости или p-значения наблюдаемого различия между эффектами препарата и плацебо:
# Пример из книги "Statistics is Easy" Денниса Шаши и Манды Уилсон
from statistics import 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 = 10000
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 random import expovariate, gauss
from statistics import mean, median, stdev
average_arrival_interval = 5.6
average_service_time = 5.0
stdev_service_time = 0.5
num_waiting = 0
arrivals = []
starts = []
arrival = service_end = 0.0
for i in range(20000):
if arrival <= service_end:
num_waiting += 1
arrival += expovariate(1.0 / average_arrival_interval)
arrivals.append(arrival)
else:
num_waiting -= 1
service_start = service_end if num_waiting else arrival
service_time = gauss(average_service_time, stdev_service_time)
service_end = service_start + service_time
starts.append(service_start)
waits = [start - arrival for arrival, start in zip(arrivals, starts)]
print(f'Mean wait: {mean(waits):.1f}. Stdev wait: {stdev(waits):.1f}.')
print(f'Median wait: {median(waits):.1f}. Max wait: {max(waits):.1f}.')
См. также
Statistics for Hackers – видеоурок от Jake Vanderplas по статистическому анализу, использующему всего несколько фундаментальных понятий, включая моделирование, выборку, перемешивание и кросс-валидацию.
Economics Simulation – симуляция рынка от Peter Norvig, демонстрирующая эффективное использование многих инструментов и распределений, предоставляемых этим модулем (gauss, uniform, sample, betavariate, choice, triangular и randrange).
A Concrete Introduction to Probability (using Python) – учебное пособие от Peter Norvig, охватывающее основы теории вероятностей, написание симуляций и выполнение анализа данных с помощью Python.