Основные операции с массивами NumPy#

import numpy as np

Копирование#

В языке Python всё является объектом. Чтобы не замедлять работу интерпретатора принято следующее соглашение: сложные объекты по умолчанию не копируются (не клонируются). Вместо этого выполняются операции со ссылками на объекты.

В чём это выражается в контексте работы с NumPy? Создадим один массив и затем присвоим его другой переменной:

a = np.arange(10)
b = a
print("a =", a)
print("b =", b)
a = [0 1 2 3 4 5 6 7 8 9]
b = [0 1 2 3 4 5 6 7 8 9]

Вроде бы, получили то, что ожидали. Но! Изменим один из элементов массива a:

a[1] = -7

Что увидим при выводе? А вот что:

print("a =", a)
print("b =", b)
a = [ 0 -7  2  3  4  5  6  7  8  9]
b = [ 0 -7  2  3  4  5  6  7  8  9]

Изменился и массив b. И это совсем не удивительно, ведь на самом деле в b хранится не сам массив, а лишь ссылка на массив a. Изменился массив a, а ссылка b на него (его адрес в памяти компьютера) осталась той же. Всегда будьте внимательны, когда приравниваете сложные объекты друг к другу.

Ситуация ещё интереснее, поскольку мы можем изменить массив a, используя ссылку b:

b[0] = 177
print("a =", a)
print("b =", b)
a = [177  -7   2   3   4   5   6   7   8   9]
b = [177  -7   2   3   4   5   6   7   8   9]

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

Если вы хотите иметь массив b такой же, как a, но независимый от него, то на помощь приходит метод np.copy():

a = np.arange(10)
b = a.copy()

a[1] = -7
b[0] = 177

print("a =", a)
print("b =", b)
a = [ 0 -7  2  3  4  5  6  7  8  9]
b = [177   1   2   3   4   5   6   7   8   9]

Массивы изменяются независимо.

Арифметические операции#

Массивы NumPy поддерживают все арифметические операции Python и стандартной библиотеки math и даже больше!

Заведём пару массивов одинаковой формы и рассмотрим некоторые операции.

a = np.array([1., 2, 3, 4, 5])
b = np.array([-1., 0, -5, -11, 7])
a + 1
array([2., 3., 4., 5., 6.])
2 * a
array([ 2.,  4.,  6.,  8., 10.])
a / 3
array([0.33333333, 0.66666667, 1.        , 1.33333333, 1.66666667])
a ** 2
array([ 1.,  4.,  9., 16., 25.])
a ** 0.5
array([1.        , 1.41421356, 1.73205081, 2.        , 2.23606798])
a + b
array([ 0.,  2., -2., -7., 12.])
a - b
array([ 2.,  2.,  8., 15., -2.])
a * b
array([ -1.,   0., -15., -44.,  35.])
a / (2 + b)
array([ 1.        ,  1.        , -1.        , -0.44444444,  0.55555556])
a ** b
array([1.00000000e+00, 1.00000000e+00, 4.11522634e-03, 2.38418579e-07,
       7.81250000e+04])

Математика посложнее#

a = np.arange(-np.pi, np.pi + 1e-6, 2 * np.pi / 3)
np.degrees(a)
array([-180.,  -60.,   60.,  180.])
# тригонометрическим функциям аргумент нужен
# обязательно в радианах
print("sin a =", np.sin(a))
print("cos a =", np.cos(a))
print("tan a =", np.tan(a))
sin a = [-1.22464680e-16 -8.66025404e-01  8.66025404e-01  1.22464680e-16]
cos a = [-1.   0.5  0.5 -1. ]
tan a = [ 1.22464680e-16 -1.73205081e+00  1.73205081e+00 -1.22464680e-16]
np.exp(a)
array([ 0.04321392,  0.35091981,  2.84965391, 23.14069263])
b = np.random.randint(-10, 11, 5)
b
array([-5,  6,  3, -1, -9], dtype=int32)
print("min b =", b.min())
print("max b =", b.max())
min b = -9
max b = 6
# индексы мин. и макс. элементов
print("argmin b =", b.argmin())
print("argmax b =", b.argmax())
argmin b = 4
argmax b = 1
# сумма элементов
b.sum()
np.int64(-6)

Стоит отметить, что функции sin, cos и прочие являются универсальными функциями NumPy. Универсальны они потому, что позволяют работать как с массивами, так и обычными числами.

Операции с двумерными массивами#

В NumPy имеется понятие оси (axis). Ось 0 обозначает строки, ось 1 означает столбцы и т.д.

a = np.arange(12).reshape((3, 4))
a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
# сумма элементов по строкам,
# т.е. суммируются элементы в столбцах
a.sum(axis=0)
array([12, 15, 18, 21])
# аналогично сумма элементов по столбцам
a.sum(axis=1)
array([ 6, 22, 38])
print("min(axis=0) =", a.min(axis=0))
print("min(axis=1) =", a.min(axis=1))
min(axis=0) = [0 1 2 3]
min(axis=1) = [0 4 8]