-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumpy_random.txt
187 lines (139 loc) · 16 KB
/
numpy_random.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
============Случайные числа============
Случайное число — это число, которое возникает в результате случайного процесса.
Псевдослучайные числа — это такая последовательность чисел, которая возникает с помощью применения математических формул к какому-то исходному числу (например, текущему времени в микросекундах). Элементы, получаемые таким образом, почти не зависят друг от друга: например, при генерации следующего 0 или 1 не имеет значения, что выпало ранее — 0 или 1.
============Случайные числа в NumPy============
======Генерация float======
Для генерации псевдослучайных чисел в NumPy существует подмодуль random.
Самой «базовой» функцией в нём можно считать функцию rand. По умолчанию она генерирует число с плавающей точкой между 0 (включительно) и 1 (не включительно):
import numpy as np
np.random.rand()
# 0.06600758835806675
Чтобы получить случайное число в диапазоне, например, от 0 до 100, достаточно просто умножить генерируемое число на 100:
np.random.rand() * 100
# 69.76076924077643
На самом деле rand умеет генерировать не только отдельные числа — функция принимает в качестве аргументов через запятую целые числа, которые задают форму генерируемого массива. Например, получим массив из пяти случайных чисел:
np.random.rand(5)
# array([0.83745099, 0.58426808, 0.89206204, 0.41149807, 0.42445145])
Массив из двух случайных строк и трёх столбцов:
np.random.rand(2, 3)
# array([[0.94931212, 0.06680018, 0.26707599],
# [0.67908873, 0.18001743, 0.97732239]])
Функция rand может принимать неограниченное число целых чисел для задания формы массива:
np.random.rand(2, 3, 4, 10, 12, 23)
Обратите внимание, что обычно форму массивов мы задавали в функциях NumPy одним числом или кортежем, а не перечисляли её в виде аргументов через запятую.
Если передать в rand кортеж, возникнет ошибка:
shape = (3, 4)
np.random.rand(shape)
# TypeError: 'tuple' object cannot be interpreted as an integer
# Ошибка типов: кортеж не может быть интерпретирован как целое число.
Конечно, можно было бы распаковать кортеж, чтобы избавиться от ошибки:
shape = (3, 4)
np.random.rand(*shape)
# array([[0.66169176, 0.19455777, 0.06451088, 0.31919608],
# [0.73536951, 0.67104408, 0.4762727 , 0.88153576],
# [0.70672971, 0.96677145, 0.09273995, 0.86356465]])
Но в NumPy есть и другая функция, генерирующая массивы случайных чисел от 0 до 1, которая принимает в качестве аргумента именно кортеж без распаковки. Она называется sample:
shape = (2, 3)
np.random.sample(shape)
# array([[0.39756103, 0.01995168, 0.2768951 ],
# [0.82195372, 0.26435273, 0.00957881]])
Возможно, именно функция sample покажется вам удобнее, поскольку информацию о форме массива обычно удобнее хранить в коде в виде кортежа и не задумываться потом о его распаковке. В остальном функция sample не отличается от rand.
Не всегда требуются числа в диапазоне именно от 0 до 1. На самом деле с помощью специальных формул можно из диапазона от 0 до 1 получить любой другой желаемый диапазон, однако это не требуется делать самостоятельно — в NumPy доступна функция uniform:
uniform(low=0.0, high=1.0, size=None)
Первые два аргумента — нижняя и верхняя границы диапазона в формате float, третий опциональный аргумент — форма массива (если не задан, возвращается одно число). Форма массива задаётся кортежем или одним числом.
Запуск без аргументов эквивалентен работе функций rand или sample:
np.random.uniform()
# 0.951557685543591
Зададим границы диапазона от -30 до 50:
np.random.uniform(-30, 50)
# 38.47365525953661
Получим пять чисел в интервале от 0.5 до 0.75:
np.random.uniform(0.5, 0.75, size=5)
# array([0.58078945, 0.58860342, 0.73790553, 0.63448265, 0.70920297])
Получим массив из двух строк и трёх столбцов из чисел в интервале от -1000 до 500:
np.random.uniform(-1000, 500, size=(2, 3))
# array([[ 129.22164163, 77.69090611, -132.9656972 ],
# [ 18.65802226, -317.14793906, 85.3613547 ]])
======Генерация int======
Не всегда требуется генерировать числа с плавающей точкой. Иногда бывает удобно получить целые числа int (например, для поля игры в лото). Для генерации целых чисел используется функция random.randint:
randint(low, high=None, size=None, dtype=int)
Функцию randint нельзя запустить совсем без параметров, необходимо указать хотя бы одно число.
- Если указан только аргумент low, числа будут генерироваться от 0 до low-1, то есть верхняя граница не включается.
- Если задать low и high, числа будут генерироваться от low (включительно) до high (не включительно).
- size задаёт форму массива уже привычным для вас образом: одним числом — для одномерного или кортежем — для многомерного.
- dtype позволяет задать конкретный тип данных, который должен быть использован в массиве.
Сгенерируем таблицу 2x3 от 0 до 3 включительно:
np.random.randint(4, size=(2,3))
# array([[3, 0, 1],
# [2, 1, 3]])
Чтобы задать и нижнюю, и верхнюю границы самостоятельно, передадим два числа, а затем форму:
np.random.randint(6, 12, size=(3,3))
# array([[ 9, 6, 10],
# [10, 11, 10],
# [ 7, 10, 11]])
Как и ожидалось, мы получили случайные числа от 6 до 11. Число 12 при этом никогда не было бы сгенерировано, так как верхняя граница диапазона не включена в генерацию.
======Генерация выборок======
→ Случайные числа можно использовать и для работы с уже существующими данными. Иногда для проверки гипотез о данных бывает удобно перемешать значения, чтобы проверить, является ли наблюдаемая закономерность случайной.
Просто перемешать все числа в массиве позволяет функция random.shuffle. (Вспомните, во многих сервисах для прослушивания музыки есть функция shuffle для перемешивания композиций в плейлисте.)
Возьмём массив из целых чисел от 0 до 5 и перемешаем его:
arr = np.arange(6)
print(arr)
# [0 1 2 3 4 5]
print(np.random.shuffle(arr))
# None
arr
# array([0, 5, 1, 3, 2, 4])
Функция random.shuffle перемешивает тот массив, к которому применяется, и возвращает None.
Чтобы получить новый перемешанный массив, а исходный оставить без изменений, можно использовать функцию random.permutation. Она принимает на вход один аргумент — или массив целиком, или одно число:
playlist = ["The Beatles", "Pink Floyd", "ACDC", "Deep Purple"]
shuffled = np.random.permutation(playlist)
print(shuffled)
# ['The Beatles' 'Pink Floyd' 'Deep Purple' 'ACDC']
print(playlist)
# ['The Beatles', 'Pink Floyd', 'ACDC', 'Deep Purple']
Обратите внимание, что необязательно передавать в функцию сразу массив: в этот раз мы передали в качестве аргумента список и ошибки не возникло. При этом на выходе получился уже NumPy-массив (это заметно по отсутствию запятых при печати массива). Сам список playlist при этом остался без изменений.
Перемешать набор чисел от 0 до n-1 можно с помощью записи np.random.permutation(n), где n — верхняя граница, которая бы использовалась для генерации набора чисел функцией arange.
np.random.permutation(10)
# array([7, 8, 2, 9, 4, 3, 1, 0, 5, 6])
По сути, вначале создаётся массив из чисел с помощью arange, а затем он перемешивается. С помощью permutation можно избежать совершения этого дополнительного действия.
→ Чтобы получить случайный набор объектов из массива, используется функция random.choice:
choice(a, size=None, replace=True)
a — одномерный массив или число для генерации arange(a);
size — желаемая форма массива (число для получения одномерного массива, кортеж — для многомерного; если параметр не задан, возвращается один объект);
replace — параметр, задающий, могут ли элементы повторяться (по умолчанию могут).
Выберем случайным образом из списка двоих человек, которые должны будут выступить с отчётом на этой неделе. Для этого из списка имён (опять же, можно передавать в функцию choice не NumPy-массив, а список) получим два случайных объекта без повторений (логично, что нужно выбрать двух разных людей). Сделать это можно вот так:
workers = ['Ivan', 'Nikita', 'Maria', 'John', 'Kate']
choice = np.random.choice(workers, size=2, replace=False)
print(choice)
На выходе получили массив из двух имён без повторений.
Если попытаться получить без повторений массив большего размера, чем имеется объектов в исходном, возникнет ошибка:
workers = ['Ivan', 'Nikita', 'Maria', 'John', 'Kate']
choice = np.random.choice(workers, size=10, replace=False)
print(choice)
# ValueError: Cannot take a larger sample than population when 'replace=False'
# Ошибка значения: нельзя получить выборку больше, чем популяция (популяция — весь доступный набор объектов, из которого получаем выборку), если replace=False (то есть выборка без повторений).
Выборка с повторениями используется по умолчанию. Она применяется в том случае, когда мы допускаем, что объекты могут повторяться.
Например, получим случайную последовательность, которая образуется в результате десяти подбрасываний игральной кости:
choice = np.random.choice([1,2,3,4,5,6], size=10)
print(choice)
# [3 5 5 6 6 4 2 2 1 3]
В данном случае ошибка не возникает за счёт того, что объекты могут повторяться.
============Seed генератора псевдослучайных чисел============
→ Как уже было сказано ранее, NumPy генерирует не истинные случайные числа (такие числа получаются в результате случайных процессов), а псевдослучайные, которые получаются с помощью особых преобразований какого-либо исходного числа. Обычно компьютер берёт это число автоматически, например, из текущего времени в микросекундах (на самом деле используются другие ещё менее предсказуемые числа). Такое число называют seed (от англ. — «зерно»).
Иногда бывает необходимо получать одинаковые воспроизводимые последовательности случайных чисел, например чтобы проверить результаты вычислений, для которых использовались случайные числа, на предмет ошибок.
Самостоятельно задать seed в NumPy можно с помощью функции np.random.seed(<np.uint32>). Число в скобках должно быть в пределах от 0 до 2**32 - 1 (=4294967295).
Зададим seed и посмотрим, что получится:
np.random.seed(23)
np.random.randint(10, size=(3,4))
# array([[3, 6, 8, 9],
# [6, 8, 7, 9],
# [3, 6, 1, 2]])
Если вы запустите этот код на своём компьютере, то, скорее всего, увидите тот же самый набор чисел!
np.random.seed(100)
print(np.random.randint(10, size=3))
# [8 8 3]
print(np.random.randint(10, size=3))
# [7 7 0]
print(np.random.randint(10, size=3))
# [4 2 5]
При этом запуск одной и той же функции генерации случайных чисел несколько раз после задания seed не приводит к генерации одних и тех же чисел. Однако итоговый результат работы всегда будет одинаковый в совокупности.