Библиотека NumPy

На страницах школьного курса мы говорили о недостатках стандартного массива List в Python, указывая, в первую очередь, на его низкую производительность. Фактически, “отраслевой” заменой массиву list является массивы библиотеки NumPy, предоставляющей высокопроизводительные алгоритмы обработки массивов, сравнимые с компилируемыми языками. Приведем небольшой пример программы для сравнения стабильной сортировки массивов List и NumPy с замером скорости работы и объема памяти, занимаемой этими объектами, для 1000000 элементов.

import numpy as np
import timeit as t
import sys
from random import randint
L = []
Size = 1000000
for j in range(Size):
    L.append(randint(10, 99))   # Получили массив List
Ar = np.array(L, dtype=np.int8) # Получили массив NumPy
print('Размеры объектов в памяти:')
print('List  ->', sys.getsizeof(L))
print('NumPy ->', sys.getsizeof(Ar))
################ Сортровка List ##################
a = t.default_timer()
L.sort()
time = t.default_timer() - a
print('Время выполнения для List  -> {:.3f}'.format(time))
############## Сортровка массива NumPy ###########
a = t.default_timer()
Ar.sort(kind='mergesort')
time = t.default_timer() - a
print('Время выполнения для NumPy -> {:.3f}'.format(time))

Вывод

Размеры объектов в памяти:
List  -> 8448728
NumPy -> 1000104
Время выполнения для List  -> 0.107
Время выполнения для NumPy -> 0.002

Приятной особенностью NumPy является вполне вразумительный способ определения типа данных элементов массива (как для целых, так и для действительных типов), что позволяет существенно (более чем в 8 раз) сократить объем используемой памяти, если необходимо хранить элементы малой ширины типа. Массив array в python тоже имеет подобные возможности, но в NumPy, на мой взгляд, используется более понятный синтаксис. Не взирая на то, что разработчики python в последних версиях существенно нарастили производительность List, тем не менее NumPy показывает пятидесятикратное превосходство по производительности!
Что же представляет из себя NumPy? NumPy – это научная библиотека, которая предоставляет объект многомерного массива и большой набор специальных функций для его обработки. Между массивами NumPy и стандартными последовательностями Python есть важные отличия:

  1. Массивы NumPy при создании имеют фиксированный размер;
  2. Все элементы в массиве NumPy имеют один и тот же тип данных и, следовательно, имеют одинаковый размер в памяти. (Но можно иметь массивы объектов, что позволяет использовать массивы элементов разного размера).

Массив NumPy – Ar, в программе выше, был создан на основе обычного массива List, в типичном стиле python. В следующей программе, перечислены другие способы инициализации массива NumPy.

import numpy as np
# 1 - Явная инициализация
Ar = np.array([1, 2, 3, 4, 5])
print('1 =>', Ar)
# 2 - С указанием целого типа (ширина 2 байт)
Ar = np.array([1, 2, 3, 4, 5], dtype=np.int16)
print('2 =>', Ar)
# 3 - С указанием действительного типа (ширина 2 байт)
Ar = np.array([1, 2, 3, 4, 5], dtype=np.float16)
print('3 =>', Ar)
# 4 - Ранжирование целых
Ar = np.arange(10, 100, 10, dtype=np.int64)
print('4 =>', Ar)
# 5 - Ранжирование действительных
Ar = np.arange(0.1, 0.8, 0.1)
print('5 =>', Ar)
# 6 - Ранжирование с отрицательными значениями
Ar = np.arange(-5, 6)
print('6 =>', Ar)
# 7 - Рандомизация целых
Ar = np.random.randint(10, 100, 10)
print('7 =>', Ar)
# 8 - Рандомизация действительных
Ar = np.random.rand(10)
print('8 =>', Ar)
# 9 - Рандомизация на отрезке [a, b) по формуле:
# (b - a) * random_sample() + a
Ar = 10 * np.random.random_sample(10) - 5
print('9 =>', Ar)
# 10 - Массив нулевых значений
Ar = np.zeros(10, dtype=np.byte)
print('10 =>', Ar)

Вывод:

1 => [1 2 3 4 5]
2 => [1 2 3 4 5]
3 => [1. 2. 3. 4. 5.]
4 => [10 20 30 40 50 60 70 80 90]
5 => [0.1 0.2 0.3 0.4 0.5 0.6 0.7]
6 => [-5 -4 -3 -2 -1  0  1  2  3  4  5]
7 => [93 96 75 58 12 90 16 22 21 48]
8 => [0.25654758 0.2743223  0.56383247 0.44199293 0.34784903 0.66442022 0.68438964 0.63694037 0.63224638 0.82797918]
9 => [ 3.03670668  4.47320688 -0.26251012  3.17943722  3.16389912 -4.91981051  -1.93778032  0.15214871 -4.91833127  4.90292445]
10 => [0 0 0 0 0 0 0 0 0 0]

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

import numpy as np
# Явная инициализация
Ar1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(Ar1)
# Заполнение случайными числами
Ar2 = np.floor(10 * np.random.randn(3, 3))
print(Ar2)
# Ранжирование
Ar3 = np.arange(1, 10).reshape(3, 3)
print(Ar3)
# Единичная матрица
Ar4 = np.ones((3, 3), dtype=np.byte)
print(Ar4)
# Сложение матриц
Ar = Ar3 + Ar4
print(Ar)
# Вычитание матриц
Ar = Ar3 - Ar4
print(Ar)
# Умножение матрицы на число
Ar = 3 * Ar
print(Ar)
# Умножение матриц
Ar = Ar @ Ar3
print(Ar)
# Транспонирование матрицы
Ar = np.transpose(Ar)
print(Ar)

Вывод:

[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[ -6. -19.  -7.]
 [ -3. -17. -16.]
 [  0. -14.   6.]]
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[1 1 1]
 [1 1 1]
 [1 1 1]]
[[ 2  3  4]
 [ 5  6  7]
 [ 8  9 10]]
[[0 1 2]
 [3 4 5]
 [6 7 8]]
[[ 0  3  6]
 [ 9 12 15]
 [18 21 24]]
[[ 54  63  72]
 [162 198 234]
 [270 333 396]]
[[ 54 162 270]
 [ 63 198 333]
 [ 72 234 396]]

В тех программах на Python, в которых производится работа с массивами и нужна скорость, несомненно, необходимо использовать массивы NumPy, вместо медленного List. Впрочем, разработчики самого Python не стесняются это признавать. Таким образом, любая серьезная разработка на языке python не обходится без NumPy. На сайте библиотеки вы найдете подробную документацию и множество примеров использования NumPy.
Массивы NumPy часто применяются для отрисовки графиков с другой известной библиотекой Matplotlib. Ниже демонстрируется простой пример вывода синусоиды с помощью этих двух библиотек.

import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
Ar = np.sin(10 * np.linspace(0, 1))
ax.plot(Ar, '-o', ms=10, alpha=0.7, mfc='red')
ax.grid()
plt.show()

Вывод:

О библиотеке Matplotlib мы расскажем в отдельной статье.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.


Обсуждение закрыто.