Модуль random в Python

Модуль random в Python

easy
Вам может быть интересно:

И почему случайности в программировании неслучайны

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

Эта статья — больше про теорию. Если хотите программировать, вот несколько наших проектов на Python с использованием генератора случайных чисел:

Введение в модуль random

Когда программе на Python нужна работа с какими-то случайными элементами, подключают модуль random. Это встроенная возможность языка программирования, которую можно добавить в код и использовать несколькими способами.

Компьютеры не могут генерировать по-настоящему случайные числа. Это потому, что все программы работают по заранее определённым алгоритмам. А алгоритмы работают на основе начального значения и математических формул, которые всегда выдают одну и ту же последовательность чисел при одинаковом начальном значении. Такие алгоритмы называются детерминированными — это значит, что результаты можно повторить.

Получается, что модуль random на самом деле — генератор псевдослучайных чисел, или ГПСЧ. Всё, что могут сделать ГПСЧ, — генерировать псевдослучайные числа. Каждый такой генератор имеет период — количество чисел, которые генератор может сгенерировать, прежде чем последовательность начнёт повторяться. Из-за того что генераторы псевдослучайных чисел используют алгоритмы, их последовательности всегда в конечном итоге цикличны. Для некоторых задач с большими объёмами данных важен длинный период, потому что короткий может привести к ошибкам.

Random работает на одном из самых популярных ГПСЧ-алгоритмов — вихре Мерсенна. Это быстрый и простой в использовании алгоритм с длинным периодом — примерно 4,3 × 106001. Это настолько длинный период, что даже при генерации миллиардов чисел в секунду он не завершится за несколько миллиардов лет.

Где взять истинно случайные числа и когда они нужны

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

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

Теперь возвращаемся в реальности программирования.

Импортирование модуля random

В Python random встроен по умолчанию, и отдельно скачивать его не нужно, а добавить в программу модуль можно по-разному. 

Первый вариант — импортировать все функции из модуля командой:

from random import *

Теперь функции из модуля можно вызывать просто как уже существующие где-то в коде. Такая программа:

random_integer = randint(0, 100)

print(random_integer)

выведет случайное число от 1 до 100.

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

Второй вариант — импортировать модуль с конкретным указанием имени: 

import random

Теперь при вызове функций модуля будет сразу видно, откуда эта функция, потому что в начале будет стоять random:

random.randint

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

Ещё это удобно, потому что можно использовать любые функции из модуля и не подключать их отдельно. 

Третий вариант — импортировать конкретную функцию:

from random import shuffle

Подключённая таким образом функция может вызываться напрямую, как при импорте всех функций через *. Этот код выведет перемешанную случайным образом последовательность чисел от 1 до 5:

sequence = [1, 2, 3, 4, 5]

shuffle(sequence)

print(sequence)

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

Основные функции модуля random

Главный способ использования random — генерация случайных чисел. Для этого можно использовать несколько функций:

  • random.random();
  • random.randint(a, b);
  • random.randrange(start, stop, step);
  • random.uniform(a, b);
  • normalvariate(mu, sigma);
  • lognormalvariate(mu, sigma);
  • random(expovaraite).

Сейчас разберём каждую из них подробнее.

Random.random()

Базовая функция модуля, которая возвращает вещественное дробное число от 0 до 1. Точка в такие числах может находиться на разных позициях — говорят, что она может плавать. На основе возвращаемого числа с плавающей точкой из функции random можно построить более сложные алгоритмы.

При использовании этой функции нужно помнить, что компьютеры возвращают искусственно сгенерированные псевдослучайные числа. Псевдослучайные числа зависят от инициализирующего числа seed, которое берётся за основу генерации. Например, если значение seed всегда равно 3, то генерируемые числа при каждом запуске программы будут одинаковыми. Это обеспечивает повторную воспроизводимость, но не подходит для ситуаций, когда нужны по-настоящему случайные числа.

Вот пример. Инициализирующее число устанавливается командой random.seed(5). После этого каждый раз при запуске программы компьютер будет выдавать одни и те же варианты случайных чисел:

import random
random.seed(5)
print(random.random())
print(random.random())

В этом коде мы будем получать два числа в консоли, выведенных командой print():

0.6229016948897019

0.7417869892607294

Но если программу запустить повторно, числа будут те же. Любой другой человек тоже получит такие же результаты. Так происходит потому, что мы используем фиксированное стартовое число seed.

Random.randint(a, b)

Используется для генерации случайного целого числа в заданном диапазоне. В скобках задаются нижняя и верхняя граница диапазона:

import random
r = random.randint(1, 50)
print(f"Случайное число между 1 и 50 равно: {r}")

С функцией randint каждый раз при запуске числа будут получаться разные.

Random.randrange(start, stop, step)

Генерирует случайное целое число из диапазона от start до stop, не включая stop, с указанным шагом step.

Функцию можно применить для получения одного числа:

import random

num = random.randrange(5, 20, 3)
print(num)

Мы получаем числа в промежутке от 5 до 20. Но мы выставили шаг 3, поэтому в консоли увидим только одно число. Чтобы шаг проявился, надо запросить несколько чисел. Например, создать цикл из 10 повторений, где каждым повторением будет получение нового случайного числа:

import random

for _ in range(10):
    num = random.randrange(5, 20, 3)
    print(num)

Теперь Питон выведет в консоли 10 чисел с минимальным шагом между ними в 3:

5
8
11
17
17
11
11
8
5
11

Random.uniform(a, b)

Возвращает случайное число с плавающей точкой в положительном или отрицательном диапазоне от a до b. Это аналог функции randint, но для дробных чисел:

import random

function = random.uniform(1, 10)
print(function)

В консоли получаем:

2.1066833318272717

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

Normalvariate(mu, sigma)

Эта функция посложнее. Сначала посмотрим на определение, а потом разберём его подробнее.

Функция normalvariate() генерирует случайное число, соответствующее нормальному распределению с параметрами:

  • mu — среднее значение;
  • sigma — стандартное отклонение.

Теперь понятным языком.

Нормальное распределение — это способ описания, как значения распределяются вокруг среднего. Представьте график «колокол», который показывает, что большинство значений находятся около среднего, а значения далеко от него встречаются реже:

Модуль random в Python

Например, у большинства людей рост близок к среднему, а людей с очень маленьким или очень большим ростом гораздо меньше. Среднее значение — центр этого нормального распределения. Если брать средний рост человека за 165 сантиметров, то среднее значение будет равно 165.

Стандартное отклонение показывает, как много существует значений относительно среднего. В примере с ростом при отклонении в 5 сантиметров почти все люди будут иметь рост от 160 до 170. При большом отклонении график может сильно варьироваться, например от 140 до 190.

Так это выглядит в коде, если запросить значение из примера с ростом людей и средним значением в 165 и отклонением в 10:

import random

height = random.normalvariate(165, 10)
print(height)

В консоли получаем:

154.7791414063284

Normalvariate() используется в моделировании реальных данных, которые следуют нормальному распределению.

Lognormalvariate(mu, sigma)

Генерирует случайное число, следующее логнормальному распределению. 

На графике это распределение выглядит так:

Модуль random в Python
Источник: agricolamz.github.io

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

  1. Значения не могут быть отрицательными — деньги, расстояния, время выполнения задачи.
  2. Большинство значений маленькие, но иногда встречаются очень большие — доходы людей, цены акций.

Аргументы функции:

  1. mu — среднее значение логарифма чисел, но не самих чисел. Это значение определяет центр распределения.
  2. sigma — стандартное отклонение логарифма чисел. Оно показывает, насколько сильно разбросаны значения.

Пример с моделированием случайного числа из графика доходов с медианой 50 000 и разбросом 0.5. Логарифм от 50 000 равен 10.82, поэтому в коде используем это число:

import random

generate = random.lognormvariate(10.82, 0.5) 
print(generate)

Вывод в консоли:

51626.559880447705

Random.expovariate(lambd)

Генерирует случайное число, которое следует экспоненциальному распределению. Это распределение описывает время ожидания между случайными событиями, которые происходят с постоянной вероятностью.

Постоянная вероятность означает, что событие всегда может произойти. Случайное — значит, неизвестно, когда именно. Например, лампочка обязательно перегорит, но неизвестно когда.

Параметр lambd определяет интенсивность этого постоянного события, которое считается как 1/lambd.

Пример: подсчитываем время между звонками в кол-центр. Они случаются постоянно, но с разными промежутками. Таким кодом мы выводим 5 разных периодов ожидания, если среднее время между звонками — 5 минут. Получается, что lambd = 1/5 = 0,2:

import random

for _ in range(5):
    time_between_calls = random.expovariate(0.2)
    print(time_between_calls)

Смотрим на вывод:

4.841418981574285

6.850636624078384

17.073970255636386

7.3094585831571965

9.294306255155155

Большинство результатов близко друг к другу, но иногда встречаются большие значения, например 17,073970255636386.

Работа с коллекциями

Коллекция в Python — объекты, которые хранят последовательности, значения одного или нескольких типов. Это могут быть строки, числа, другие коллекции. Для работы с коллекциями в random есть несколько функций:

  • random.choice(seq);
  • random.sample(population, k);
  • random.shuffle(seq).

Дальше разбираем каждую подробнее.

Random.choice(seq)

Выбирает один псевдослучайный элемент (seq) из переданной последовательности. Функция работает с любыми коллекциями, возвращает один элемент и выбрасывает ошибку, если последовательность пуста.

Создаём список имён и выбираем случайное:

import random

names = ["Миша", "Инна", "Кристина", "Ранд"]

random_name = random.choice(names)
print(f"Случайно выбранное имя: {random_name}")

В консоли получаем:

Случайно выбранное имя: Кристина

Random.sample(population, k)

Возвращает список из k случайных уникальных элементов из переданной последовательности population.

Функция не берёт один и тот же элемент последовательности дважды, но принимает коллекции с дублирующимися элементами и может возвращать два одинаковых элемента, если в коллекции такие есть. 

Sample() не изменяет оригинальную последовательность и выбросит ошибку, если k больше длины population. 

Пример со списком из чисел от 1 до 9. Попросим у функции 3 случайных числа:

import random

functions = [1, 2, 3, 4, 5, 6, 7, 8, 9]

random_numbers = random.sample(functions, 3)
print(f"Случайные числа: {random_numbers}")

Смотрим на результат:

Случайные числа: [6, 2, 8]

Random.shuffle(seq)

Перемешивает случайным образом элементы в последовательности seq.

Функция может работать только с изменяемыми последовательностями, например списками. Изменяет исходную последовательность.

Перемешиваем список из 5 чисел:

import random

list = [1, 2, 3, 4, 5]
random.shuffle(list)
print(f"Перемешанный список: {list}")

Вывод в консоли:

Перемешанный список: [4, 2, 5, 3, 1]

Дополнительные функции модуля random

Вот ещё три настройки, которые могут пригодиться в работе.

Random.seed() задаёт начальное состояние генератора псевдослучайных чисел. Тогда результаты всех функций будут одинаковыми при повторном запуске программы. Это полезно, если другой человек хочет воспроизвести результаты вашей работы у себя.

Getstate() позволяет получить и сохранить состояние генератора seed, чтобы потом можно было к нему вернуться. Так мы сохраняем это состояние в переменную state:

state = random.getstate()

Setstate() позволяет установить новое состояние в процессе выполнения программы. Так можно восстановить состояние генератора из переменной state:

random.setstate(state)

Как часто пользуются random в реальной разработке

Использовать ГПСЧ или истинно случайные числа — зависит от задачи. Вот несколько примеров, где применяется random:

  • Генерация уникальных идентификаторов, например номера элементов.
  • Перемешивание существующих элементов в случайном порядке.
  • В криптографии можно применять random и создавать ключи шифрования.
  • Моделирование с определёнными распределениями значений.
  • Генерация случайных чисел через random — помогает предоставлять нужные данные для обучения и тестирования моделей машинного обучения.

Примеры применения module random

Из-за своей псевдослучайности random подходит не для всех задач, но для некоторых — годится. Вот несколько наших проектов:

  • В проекте игры блек-джек на Python мы используем random для перемешивания карт и потом достаём по одной. Это не чистая случайность, поэтому похоже на игру в реальном казино, но не совсем.
  • Для игры в тетрис random генерирует случайную следующую фигуру.
  • В программе подготовки к экзаменам мы сделали так: подготовили билеты с вариантами ответов и выводили вопросы и ответы в случайном порядке.

Как ещё можно генерировать псевдослучайные числа

Другой вариант генерации псевдослучайности на Питоне — подключение библиотеки NumPy. Это более серьёзный вариант, который используется при работе с аналитикой и большим количество информации в Big Data.

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Кирилл Климентьев

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Вам может быть интересно
easy