random — Generate pseudo-random numbers

Вихідний код: Lib/random.py


Цей модуль реалізує генератори псевдовипадкових чисел для різних розподілів.

Для цілих чисел існує рівномірний вибір із діапазону. Для послідовностей існує рівномірний вибір випадкового елемента, функція для створення випадкової перестановки списку на місці та функція для випадкової вибірки без заміни.

На реальній лінії існують функції для обчислення рівномірного, нормального (гауссового), логарифмічного нормального, від’ємного експоненціального, гамма- та бета-розподілу. Для генерації розподілу кутів доступний розподіл фон Мізеса.

Almost all module functions depend on the basic function random(), which generates a random float uniformly in the half-open range 0.0 <= X < 1.0. Python uses the Mersenne Twister as the core generator. It produces 53-bit precision floats and has a period of 2**19937-1. The underlying implementation in C is both fast and threadsafe. The Mersenne Twister is one of the most extensively tested random number generators in existence. However, being completely deterministic, it is not suitable for all purposes, and is completely unsuitable for cryptographic purposes.

Функції, які надає цей модуль, насправді є зв’язаними методами прихованого екземпляра класу random.Random. Ви можете створити власні екземпляри Random, щоб отримати генератори, які не мають спільного стану.

Class Random can also be subclassed if you want to use a different basic generator of your own devising: see the documentation on that class for more details.

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

Попередження

Псевдовипадкові генератори цього модуля не слід використовувати з метою безпеки. Щоб отримати відомості про безпеку чи криптографію, перегляньте модуль secrets.

Дивись також

M. Matsumoto and T. Nishimura, «Mersenne Twister: 623-dimensionally equidistributed uniform pseudorandom number generator», ACM Transactions on Modeling and Computer Simulation Vol. 8, № 1, січень 3-30 1998.

Complementary-Multiply-with-Carry recipe for a compatible alternative random number generator with a long period and comparatively simple update operations.

Бухгалтерські функції

random.seed(a=None, version=2)

Ініціалізуйте генератор випадкових чисел.

Якщо a пропущено або None, використовується поточний системний час. Якщо джерела випадковості надаються операційною системою, вони використовуються замість системного часу (дивіться функцію os.urandom(), щоб дізнатися більше про доступність).

Якщо a є int, воно використовується безпосередньо.

У версії 2 (за замовчуванням) об’єкт str, bytes або bytearray перетворюється на int і використовуються всі його біти.

У версії 1 (надається для відтворення випадкових послідовностей зі старих версій Python) алгоритм для str і bytes генерує вужчий діапазон початкових значень.

Змінено в версії 3.2: Перенесено на схему версії 2, яка використовує всі біти початкового рядка.

Змінено в версії 3.11: The seed must be one of the following types: None, int, float, str, bytes, or 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])

Return a randomly selected element from range(start, stop, step). This is equivalent to choice(range(start, stop, step)), but doesn’t actually build a range object.

The positional argument pattern matches that of range(). Keyword arguments should not be used because the function may use them in unexpected ways.

Змінено в версії 3.2: randrange() більш складний у створенні рівномірно розподілених значень. Раніше він використовував такий стиль, як int(random()*n), який міг створити дещо нерівномірний розподіл.

Застаріло починаючи з версії 3.10: The automatic conversion of non-integer types to equivalent integers is deprecated. Currently randrange(10.0) is losslessly converted to randrange(10). In the future, this will raise a TypeError.

Застаріло починаючи з версії 3.10: The exception raised for non-integer values such as randrange(10.5) or randrange('10') will be changed from ValueError to TypeError.

random.randint(a, b)

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

random.getrandbits(k)

Returns a non-negative Python integer with k random bits. This method is supplied with the MersenneTwister generator and some other generators may also provide it as an optional part of the API. When available, getrandbits() enables randrange() to handle arbitrarily large ranges.

Змінено в версії 3.9: Цей метод тепер приймає нуль для k.

Функції для послідовностей

random.choice(seq)

Повертає випадковий елемент із непорожньої послідовності seq. Якщо seq порожній, викликає IndexError.

random.choices(population, weights=None, *, cum_weights=None, k=1)

Повертає список елементів розміром k, вибраних із популяції із заміною. Якщо популяція порожня, викликає IndexError.

Якщо вказано послідовність ваг, вибір робиться відповідно до відносних ваг. Крім того, якщо вказано послідовність cum_weights, вибір робиться відповідно до кумулятивних ваг (можливо, обчислених за допомогою itertools.accumulate()). Наприклад, відносні ваги [10, 5, 30, 5] еквівалентні кумулятивним вагам [10, 15, 45, 50]. Внутрішньо відносні ваги перетворюються на кумулятивні ваги перед вибором, тому надання кумулятивних ваг економить роботу.

Якщо ані weights, ані cum_weights не вказано, вибір робиться з рівною ймовірністю. Якщо надається послідовність ваг, вона має бути такої ж довжини, що й послідовність населеності. Це TypeError, якщо вказати weights і cum_weights.

Weights або cum_weights можуть використовувати будь-який числовий тип, який взаємодіє зі значеннями float, які повертає random() (це включає цілі числа, числа з плаваючою точкою та дроби, але виключає десяткові). Ваги вважаються невід’ємними та кінцевими. Помилка ValueError виникає, якщо всі ваги дорівнюють нулю.

For a given seed, the choices() function with equal weighting typically produces a different sequence than repeated calls to choice(). The algorithm used by choices() uses floating point arithmetic for internal consistency and speed. The algorithm used by choice() defaults to integer arithmetic with repeated selections to avoid small biases from round-off error.

Нове в версії 3.6.

Змінено в версії 3.9: Викликає ValueError, якщо всі ваги дорівнюють нулю.

random.shuffle(x)

Перемішайте послідовність x на місці.

Щоб перетасувати незмінну послідовність і повернути новий перетасований список, замість цього використовуйте sample(x, k=len(x)).

Зауважте, що навіть для невеликого len(x) загальна кількість перестановок x може швидко зрости більше, ніж період більшості генераторів випадкових чисел. Це означає, що більшість перестановок довгої послідовності ніколи не можуть бути згенеровані. Наприклад, послідовність довжиною 2080 є найбільшою, яка може поміститися в період генератора випадкових чисел Мерсенна Твістера.

Змінено в версії 3.11: Removed the optional parameter random.

random.sample(population, k, *, counts=None)

Return a k length list of unique elements chosen from the population sequence. Used for random sampling without replacement.

Повертає новий список, що містить елементи з сукупності, залишаючи вихідну сукупність без змін. Отриманий список складається в порядку відбору, тому всі підзрізи також будуть дійсними випадковими вибірками. Це дозволяє розділити переможців розіграшу (зразок) на головний приз і переможців, які посідають друге місце (підрозділи).

Члени сукупності не повинні бути hashable або унікальними. Якщо популяція містить повтори, то кожен випадок є можливим вибором у вибірці.

Повторювані елементи можна вказувати по одному або за допомогою необов’язкового параметра counts, що містить лише ключове слово. Наприклад, sample(['red', 'blue'], counts=[4, 2], k=5) еквівалентно sample(['red', 'red', 'red' , 'червоний', 'синій', 'синій'], k=5).

Щоб вибрати вибірку з діапазону цілих чисел, використовуйте об’єкт range() як аргумент. Це особливо швидко та ефективно для вибірки з великої сукупності: sample(range(10000000), k=60).

Якщо розмір вибірки більший за розмір сукупності, виникає помилка ValueError.

Змінено в версії 3.9: Додано параметр counts.

Змінено в версії 3.11: The population must be a sequence. Automatic conversion of sets to lists is no longer supported.

Дійсні розподіли

Наступні функції генерують конкретні дійсні розподіли. Параметри функції називаються за відповідними змінними в рівнянні розподілу, як це використовується в звичайній математичній практиці; більшість із цих рівнянь можна знайти в будь-якому статистичному тексті.

random.random()

Return the next random floating point number in the range 0.0 <= X < 1.0

random.uniform(a, b)

Return a random floating point number N such that a <= N <= b for a <= b and b <= N <= a for b < a.

The end-point value b may or may not be included in the range depending on floating-point rounding in the expression a + (b-a) * random().

random.triangular(low, high, mode)

Return a random floating point number N such that low <= N <= high and with the specified mode between those bounds. The low and high bounds default to zero and one. The mode argument defaults to the midpoint between the bounds, giving a symmetric distribution.

random.betavariate(alpha, beta)

Бета-розповсюдження. Умови параметрів: альфа > 0 і бета > 0. Діапазон повернених значень від 0 до 1.

random.expovariate(lambd)

Експоненціальний розподіл. lambd дорівнює 1,0, поділеному на бажане середнє. Воно повинно бути відмінним від нуля. (Параметр мав би назву «лямбда», але це зарезервоване слово в Python.) Повернені значення варіюються від 0 до нескінченності, якщо lambd додатне, і від нескінченності до 0, якщо lambd є від’ємним.

random.gammavariate(alpha, beta)

Gamma distribution. (Not the gamma function!) The shape and scale parameters, alpha and beta, must have positive values. (Calling conventions vary and some sources define „beta“ as the inverse of the scale).

Функція розподілу ймовірностей:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha
random.gauss(mu=0.0, sigma=1.0)

Normal distribution, also called the Gaussian distribution. mu is the mean, and sigma is the standard deviation. This is slightly faster than the normalvariate() function defined below.

Примітка щодо багатопоточності: коли два потоки викликають цю функцію одночасно, можливо, вони отримають однакове повернуте значення. Цього можна уникнути трьома способами. 1) Нехай кожен потік використовує окремий екземпляр генератора випадкових чисел. 2) Заблокуйте всі дзвінки. 3) Натомість використовуйте повільнішу, але потокобезпечну функцію normalvariate().

Змінено в версії 3.11: mu and sigma now have default arguments.

random.lognormvariate(mu, sigma)

Лог нормального розподілу. Якщо взяти натуральний логарифм цього розподілу, ви отримаєте нормальний розподіл із середнім mu і стандартним відхиленням sigma. mu може мати будь-яке значення, а sigma має бути більше нуля.

random.normalvariate(mu=0.0, sigma=1.0)

Нормальний розподіл. mu — середнє, а sigma — стандартне відхилення.

Змінено в версії 3.11: mu and sigma now have default arguments.

random.vonmisesvariate(mu, kappa)

mu — середній кут, виражений у радіанах між 0 і 2*pi, а kappa — параметр концентрації, який має бути більшим або дорівнювати нулю. Якщо kappa дорівнює нулю, цей розподіл зменшується до рівномірного випадкового кута в діапазоні від 0 до 2*pi.

random.paretovariate(alpha)

Розподіл Парето. альфа — це параметр форми.

random.weibullvariate(alpha, beta)

Розподіл Вейбулла. альфа — параметр масштабу, а бета — параметр форми.

Альтернативний генератор

class random.Random([seed])

Клас, який реалізує генератор псевдовипадкових чисел за замовчуванням, який використовується модулем random.

Змінено в версії 3.11: Formerly the seed could be any hashable object. Now it is limited to: None, int, float, str, bytes, or bytearray.

Subclasses of Random should override the following methods if they wish to make use of a different basic generator:

seed(a=None, version=2)

Override this method in subclasses to customise the seed() behaviour of Random instances.

getstate()

Override this method in subclasses to customise the getstate() behaviour of Random instances.

setstate(state)

Override this method in subclasses to customise the setstate() behaviour of Random instances.

random()

Override this method in subclasses to customise the random() behaviour of Random instances.

Optionally, a custom generator subclass can also supply the following method:

getrandbits(k)

Override this method in subclasses to customise the getrandbits() behaviour of Random instances.

class random.SystemRandom([seed])

Клас, який використовує функцію os.urandom() для генерації випадкових чисел із джерел, наданих операційною системою. Доступно не на всіх системах. Не залежить від стану програмного забезпечення, і послідовності не відтворюються. Відповідно, метод seed() не має ефекту та ігнорується. Методи getstate() і setstate() під час виклику викликають NotImplementedError.

Примітки щодо відтворюваності

Sometimes it is useful to be able to reproduce the sequences given by a pseudo-random number generator. By re-using a seed value, the same sequence should be reproducible from run to run as long as multiple threads are not running.

Більшість алгоритмів і функцій заповнення випадкового модуля можуть змінюватися в різних версіях 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.
>>> 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)])

Дивись також

Statistics for Hackers відеоурок від Jake Vanderplas зі статистичного аналізу з використанням лише кількох фундаментальних концепцій, включаючи моделювання, вибірку, перетасування та перехресну перевірку.

Economics Simulation a simulation of a marketplace by Peter Norvig that shows effective use of many of the tools and distributions provided by this module (gauss, uniform, sample, betavariate, choice, triangular, and randrange).

A Concrete Introduction to Probability (using Python) a tutorial by Peter Norvig covering the basics of probability theory, how to write simulations, and how to perform data analysis using Python.

рецепти

These recipes show how to efficiently make random selections from the combinatoric iterators in the itertools module:

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).)

Дивись також

Generating Pseudo-random Floating-Point Values стаття Аллена Б. Дауні, яка описує способи генерації більш дрібнозернистих значень з плаваючою комою, ніж зазвичай генерує random().