Автор оригинала: 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 ()
, используется в анализе отказов, промышленной инженерии и прогнозировании погоды. Он описывает распределение размеров частиц или других дискретных объектов.
Смотрите также
- Стандартная библиотека документации для случайного выбора
- «Мерсенн Твистер: генератор равномерных псевдослучайных чисел с 623-мерным распределением» – статья М. Мацумото и Т. Нишимура из Транзакции ACM по моделированию и компьютерному моделированию Vol. 8, No. 1, январь, стр. 3-30 1998.
- Wikipedia: Mersenne Twister – статья об алгоритме псевдослучайного генератора, используемом Python.
- Википедия: Равномерное распределение – статья о непрерывных равномерных распределениях в статистике.