Рубрики
Без рубрики

random – Генераторы псевдослучайных чисел

Автор оригинала: Doug Hellmann.

Цель:

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

Модуль random предоставляет быстрый генератор псевдослучайных чисел на основе алгоритма Mersenne Twister . Первоначально разработанный для создания входных данных для моделирования методом Монте-Карло, Mersenne Twister генерирует числа с почти равномерным распределением и большим периодом, что делает его пригодным для широкого круга приложений.

Генерация случайных чисел

Функция random () возвращает следующее случайное значение с плавающей запятой из сгенерированной последовательности. Все возвращаемые значения попадают в диапазон 0 n <1.0 .

random_random.py

import random

for i in range(5):
    print('%04.3f' % random.random(), end' ')
print()

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

$ python3 random_random.py

0.859 0.297 0.554 0.985 0.452

$ python3 random_random.py

0.797 0.658 0.170 0.297 0.593

Чтобы сгенерировать числа в определенном числовом диапазоне, используйте вместо этого uniform () .

random_uniform.py

import random

for i in range(5):
    print('{:04.3f}'.format(random.uniform(1, 100)), end' ')
print()

Передайте минимальное и максимальное значения, и uniform () настроит возвращаемые значения из random () , используя формулу min + (max - min) * random () .

$ python3 random_uniform.py

12.428 93.766 95.359 39.649 88.983

Посев

random () выдает разные значения каждый раз при вызове и имеет очень большой период перед повторением любых чисел. Это полезно для получения уникальных значений или вариаций, но иногда бывает полезно иметь один и тот же набор данных, который можно обрабатывать разными способами. Один из способов – использовать программу для генерации случайных значений и сохранения их для обработки на отдельном этапе. Однако это может оказаться непрактичным для больших объемов данных, поэтому random включает функцию seed () для инициализации генератора псевдослучайных чисел, чтобы он генерировал ожидаемый набор значений.

random_seed.py

import random

random.seed(1)

for i in range(5):
    print('{:04.3f}'.format(random.random()), end' ')
print()

Начальное значение управляет первым значением, созданным формулой, используемой для создания псевдослучайных чисел, и, поскольку формула является детерминированной, она также устанавливает полную последовательность, полученную после изменения начального числа. Аргументом для seed () может быть любой хешируемый объект. По умолчанию используется зависящий от платформы источник случайности, если он доступен. В противном случае используется текущее время.

$ python3 random_seed.py

0.134 0.847 0.764 0.255 0.495

$ python3 random_seed.py

0.134 0.847 0.764 0.255 0.495

Состояние сохранения

Внутреннее состояние псевдослучайного алгоритма, используемого random () , можно сохранить и использовать для управления числами, полученными в последующих запусках. Восстановление предыдущего состояния перед продолжением снижает вероятность повторения значений или последовательностей значений из более раннего ввода. Функция getstate () возвращает данные, которые можно использовать для повторной инициализации генератора случайных чисел позже с помощью setstate () .

random_state.py

import random
import os
import pickle

if os.path.exists('state.dat'):
    # Restore the previously saved state
    print('Found state.dat, initializing random module')
    with open('state.dat', 'rb') as f:
        state  pickle.load(f)
    random.setstate(state)
else:
    # Use a well-known start state
    print('No state.dat, seeding')
    random.seed(1)

# Produce random values
for i in range(3):
    print('{:04.3f}'.format(random.random()), end' ')
print()

# Save state for next time
with open('state.dat', 'wb') as f:
    pickle.dump(random.getstate(), f)

# Produce more random values
print('\nAfter saving state:')
for i in range(3):
    print('{:04.3f}'.format(random.random()), end' ')
print()

Данные, возвращаемые функцией getstate () , являются деталью реализации, поэтому в этом примере данные сохраняются в файл с помощью pickle, но в остальном они рассматриваются как черный ящик. Если файл существует при запуске программы, он загружает старое состояние и продолжает работу. Каждый прогон производит несколько чисел до и после сохранения состояния, чтобы показать, что восстановление состояния заставляет генератор снова выдавать те же значения.

$ python3 random_state.py

No state.dat, seeding
0.134 0.847 0.764

After saving state:
0.255 0.495 0.449

$ python3 random_state.py

Found state.dat, initializing random module
0.255 0.495 0.449

After saving state:
0.652 0.789 0.094

Случайные целые числа

random () генерирует числа с плавающей запятой. Можно преобразовать результаты в целые числа, но использование randint () для генерации целых чисел напрямую более удобно.

random_randint.py

import random

print('[1, 100]:', end' ')

for i in range(3):
    print(random.randint(1, 100), end' ')

print('\n[-5, 5]:', end' ')
for i in range(3):
    print(random.randint(-5, 5), end' ')
print()

Аргументы для randint () – это концы включающего диапазона значений. Числа могут быть положительными или отрицательными, но первое значение должно быть меньше второго.

$ python3 random_randint.py

[1, 100]: 98 75 34
[-5, 5]: 4 0 5

randrange () – это более общая форма выбора значений из диапазона.

random_randrange.py

import random

for i in range(3):
    print(random.randrange(0, 101, 5), end' ')
print()

randrange () поддерживает аргумент step в дополнение к значениям start и stop, поэтому он полностью эквивалентен выбору случайного значения из диапазона (start, stop, шаг) . Это более эффективно, потому что диапазон фактически не строится.

$ python3 random_randrange.py

15 20 85

Выбор случайных предметов

Генераторы случайных чисел часто используют для выбора случайного элемента из последовательности пронумерованных значений, даже если эти значения не являются числами. random включает функцию choice () для выполнения случайного выбора из последовательности. В этом примере имитируется подбрасывание монеты 10 000 раз, чтобы подсчитать, сколько раз выпадает орел, а сколько решка.

random_choice.py

import random
import itertools

outcomes  {
    'heads': 0,
    'tails': 0,
}
sides  list(outcomes.keys())

for i in range(10000):
    outcomes[random.choice(sides)]  1

print('Heads:', outcomes['heads'])
print('Tails:', outcomes['tails'])

Допускаются только два результата, поэтому вместо использования чисел и их преобразования в choice () используются слова «орла» и «решка». Результаты заносятся в таблицу с использованием имен результатов в качестве ключей.

$ python3 random_choice.py

Heads: 5091
Tails: 4909

Перестановки

При моделировании карточной игры необходимо перемешать колоду карт и затем раздать их игрокам, не используя одну и ту же карту более одного раза. Использование choice () может привести к тому, что одна и та же карта будет сдана дважды, поэтому вместо этого колоду можно смешивать с помощью shuffle () , а затем удалять отдельные карты по мере их раздачи.

random_shuffle.py

import random
import itertools

FACE_CARDS  ('J', 'Q', 'K', 'A')
SUITS  ('H', 'D', 'C', 'S')


def new_deck():
    return [
        # Always use 2 places for the value, so the strings
        # are a consistent width.
        '{:>2}{}'.format(*c)
        for c in itertools.product(
            itertools.chain(range(2, 11), FACE_CARDS),
            SUITS,
        )
    ]


def show_deck(deck):
    p_deck  deck[:]
    while p_deck:
        row  p_deck[:13]
        p_deck  p_deck[13:]
        for j in row:
            print(j, end' ')
        print()


# Make a new deck, with the cards in order
deck  new_deck()
print('Initial deck:')
show_deck(deck)

# Shuffle the deck to randomize the order
random.shuffle(deck)
print('\nShuffled deck:')
show_deck(deck)

# Deal 4 hands of 5 cards each
hands  [[], [], [], []]

for i in range(5):
    for h in hands:
        h.append(deck.pop())

# Show the hands
print('\nHands:')
for n, h in enumerate(hands):
    print('{}:'.format(n + 1), end' ')
    for c in h:
        print(c, end' ')
    print()

# Show the remaining deck
print('\nRemaining deck:')
show_deck(deck)

Карты представлены в виде строк с номиналом и буквой, обозначающей масть. Сданные «руки» создаются путем добавления по одной карте в каждый из четырех списков и удаления ее из колоды, чтобы ее нельзя было раздать снова.

$ python3 random_shuffle.py

Initial deck:
 2H  2D  2C  2S  3H  3D  3C  3S  4H  4D  4C  4S  5H
 5D  5C  5S  6H  6D  6C  6S  7H  7D  7C  7S  8H  8D
 8C  8S  9H  9D  9C  9S 10H 10D 10C 10S  JH  JD  JC
 JS  QH  QD  QC  QS  KH  KD  KC  KS  AH  AD  AC  AS

Shuffled deck:
 QD  8C  JD  2S  AC  2C  6S  6D  6C  7H  JC  QS  QC
 KS  4D 10C  KH  5S  9C 10S  5C  7C  AS  6H  3C  9H
 4S  7S 10H  2D  8S  AH  9S  8H  QH  5D  5H  KD  8D
10D  4C  3S  3H  7D  AD  4H  9D  3D  2H  KC  JH  JS

Hands:
1:  JS  3D  7D 10D  5D
2:  JH  9D  3H  8D  QH
3:  KC  4H  3S  KD  8H
4:  2H  AD  4C  5H  9S

Remaining deck:
 QD  8C  JD  2S  AC  2C  6S  6D  6C  7H  JC  QS  QC
 KS  4D 10C  KH  5S  9C 10S  5C  7C  AS  6H  3C  9H
 4S  7S 10H  2D  8S  AH

Отбор проб

Для многих моделей необходимы случайные выборки из совокупности входных значений. Функция sample () генерирует образцы без повторения значений и без изменения входной последовательности. В этом примере печатается случайная выборка слов из системного словаря.

random_sample.py

import random

with open('/usr/share/dict/words', 'rt') as f:
    words  f.readlines()
words  [w.rstrip() for w in words]

for w in random.sample(words, 5):
    print(w)

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

$ python3 random_sample.py

streamlet
impestation
violaquercitrin
mycetoid
plethoretical

$ python3 random_sample.py

nonseditious
empyemic
ultrasonic
Kyurinish
amphide

Несколько одновременных генераторов

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

random_random_class.py

import random
import time

print('Default initializiation:\n')

r1  random.Random()
r2  random.Random()

for i in range(3):
    print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))

print('\nSame seed:\n')

seed  time.time()
r1  random.Random(seed)
r2  random.Random(seed)

for i in range(3):
    print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))

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

$ python3 random_random_class.py

Default initializiation:

0.862  0.390
0.833  0.624
0.252  0.080

Same seed:

0.466  0.466
0.682  0.682
0.407  0.407

SystemRandom

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

random_system_random.py

import random
import time

print('Default initializiation:\n')

r1  random.SystemRandom()
r2  random.SystemRandom()

for i in range(3):
    print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))

print('\nSame seed:\n')

seed  time.time()
r1  random.SystemRandom(seed)
r2  random.SystemRandom(seed)

for i in range(3):
    print('{:04.3f}  {:04.3f}'.format(r1.random(), r2.random()))

Последовательности, созданные SystemRandom , не воспроизводятся, поскольку случайность исходит от системы, а не от состояния программного обеспечения (фактически, seed () и setstate () не имеют никакого эффекта).

$ python3 random_system_random.py

Default initializiation:

0.110  0.481
0.624  0.350
0.378  0.056

Same seed:

0.634  0.731
0.893  0.843
0.065  0.177

Неравномерные распределения

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

Нормальный

нормальное распределение обычно используется для неоднородных непрерывных значений, таких как классы, высота, веса и т. Д. Кривая, полученная с помощью распределения, имеет характерную форму, которая привела к тому, что ее называют “колоколообразной кривой”. ” random включает две функции для генерации значений с нормальным распределением, normalvariate () и немного более быструю gauss () (нормальное распределение также называется распределение Гаусса).

Связанная функция lognormvariate () создает псевдослучайные значения, в которых логарифм значений распределяется нормально. Логнормальные распределения полезны для значений, которые являются продуктом нескольких случайных величин, которые не взаимодействуют.

Приближение

треугольное распределение используется как приблизительное распределение для небольших выборок. «Кривая» треугольного распределения имеет низкие точки при известных минимальных и максимальных значениях и максимальную точку в режиме, который оценивается на основе «наиболее вероятного» результата (отраженного аргументом режима в triangular () ).

Экспоненциальный

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

Распределение Парето, или степенной закон, соответствует многим наблюдаемым явлениям и было популяризировано изданием Длинный хвост Криса Андерсона. Функция paretovariate () полезна для моделирования распределения ресурсов между людьми (богатство людям, спрос на музыкантов, внимание к блогам и т. Д.).

Угловой

Распределение фон Мизеса, или круговое нормальное распределение (создается с помощью vonmisesvariate () ), используется для вычисления вероятностей циклических значений, таких как углы, календарные дни и время.

Размеры

betavariate () генерирует значения с бета-распределением, которое обычно используется в байесовской статистике и приложениях, таких как моделирование продолжительности задач.

Гамма-распределение, создаваемое gammavariate () , используется для моделирования размеров таких вещей, как время ожидания, количество осадков и вычислительные ошибки.

Распределение Вейбулла, вычисленное с помощью weibullvariate () , используется в анализе отказов, промышленной инженерии и прогнозировании погоды. Он описывает распределение размеров частиц или других дискретных объектов.

Смотрите также