Основные операции с массивами 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]