Это старая версия документа!
Числовые данные в Python
Встроенные средства Python не слишком хороши для работы с числовыми данными, поэтому для этого существуют отдельные модули. Наиболее важной из них является модуль NumPypip, высокоэффективные методы для работы с числовыми массивам.
NumPy
Ключевой компонент numpy — высокопроизводительные многомерные статические числовые массивы np.array
. Также в NumPy имеются многочисленные методы которые позволяют избежать накладных расходов при преобразовании np.array
к типам Python и обратно.
Некоторые свойства np.array
:
Свойство | Значение |
---|---|
a.ndim | Число измерений массива a |
a.shape | Размер по осям (кортеж) массива a |
a.size | Общее число элементов в a |
a.dtype | Тип данных массива a |
Создание массивов
import numpy as np
# Из списка Python
a = np.array([1,2,3,4,5])
# a == array([1, 2, 3, 4, 5])
# Заполнение нулями
a = np.zeros(5)
# a == array([ 0., 0., 0., 0., 0.])
# 5 точек от 0 до 5 включительно
a = np.linspace(0,5,5)
# a == array([ 0. , 1.25, 2.5 , 3.75, 5. ])
# Из результатов функции
def foo(i):
return i**2
Многомерные массивы
Класс np.array
также позволяет работать с многомерными массивами. При этом задается параметр shape
определяющий размерность.
import numpy as np
# Массив 2x3
a = np.zeros((2,3))
# a == array([[ 0., 0., 0.],
# [ 0., 0., 0.]])
a = np.linspace(0,5,6)
# Изменение формы массива
b = a.reshape((3,2))
# b == array([[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]])
Индексация в массиве
При индексации сохраняется порядок индексов аналогичный фигуре
import numpy as np
b = np.linspace(0,5,6).reshape((3,2))
# b == array([[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]])
# Один элемент
v = b[1,1]
# v == 3.0
# Строка
v = b[1,:]
# v == array([ 2., 3.])
# Столбец
v = b[:,1]
# v == array([ 1., 3., 5.])
# Выборка и использованием срезов
v = b[1:-1,1]
# v == array([ 3.])
В целях оптимизации срезы создают не копии np.array
, а так называемые представления (view
), поэтому меняя данные в срезе они будут меняться и в исходном массиве.
Операции
В отличии от обычных списков Python операции над массивами производятся поэлементно.
import numpy as np
b = np.linspace(0,5,6).reshape((3,2))
# b == array([[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]])
# Операция со скаляром
c = b + 2
# c == array([[ 2., 3.],
# [ 4., 5.],
# [ 6., 7.]])
# Операция с массивом того-же размера
c = b * b
# c == array([[ 0., 1.],
# [ 4., 9.],
# [ 16., 25.]])
В отличии от обычных списков Python операции над массивами производятся поэлементно.
Математические функции из math
работать с np.array
не умеют, но в модуле numpy
есть их аналоги (np.cos
, np.log10
, …).
Матричные операции
# Умножение массива на вектор
c = b*np.array([2,3])
# c == array([[ 0., 3.],
# [ 4., 9.],
# [ 8., 15.]])
# Матричное умножение
c = np.dot(b[:-1,:],b[:-1,:])
# c == array([[ 2., 3.],
# [ 6., 11.]])
# Транспонирование
с = np.copy(b.T)
# c == array([[ 0., 2., 4.],
# [ 1., 3., 5.]])
Конкатенация
b = np.linspace(0,5,6).reshape((3,2))
# b == array([[ 0., 1.],
# [ 2., 3.],
# [ 4., 5.]])
# Конкатенация по нулевой оси
d = np.r_[b[:,1],b[1,:]]
# d == array([ 1., 3., 5., 2., 3.])
# Конкатенация по первой оси
d = np.c_[b,b]
# d == array([[0., 1., 0., 1.],
# [2., 3., 2., 3.],
# [4., 5., 4., 5.]])
Итерация
NumPy предлагает альтернативный подход к итерации по всем элементам многомерного массива по сравнению с обычными вложенными циклами.
# Обычный обход. Получаем строки.
# Нужен вложенный цикл для доступа к элементам. Только чтение.
for x in b:
print(x, end=";")
# [ 0. 1.]; [ 2. 3.]; [ 4. 5.];
# Обход через np.nditer
for x in np.nditer(b):
print(x, end=" ")
# 0.0 1.0 2.0 3.0 4.0 5.0
# Обход через np.nditer с возможностью записи
for x in np.nditer(b, op_flags=['readwrite']):
x[...] = 2 * x + 2
# b == array([[ 2., 4.],
# [ 6., 8.],
# [ 10., 12.]])
# Многомерный аналог enumerate
for index, x in np.ndenumerate(b):
print(index, x, end="; ")
# (0, 0) 2.0; (0, 1) 4.0; (1, 0) 6.0; (1, 1) 8.0; (2, 0) 10.0; (2, 1) 12.0;
Операции сравнения
Применение операций сравнения (>
, <
, >=
, ⇐
, ==
, !=
) к массивам np.array
вызывает создание массива значений типа bool
соответствующего размера.
b = np.linspace(0,5,6).reshape((3,2))
# b == array([[0., 1.],
# [2., 3.],
# [4., 5.]])
t = b>3
# t == array([[False, False],
# [False, False],
# [ True, True]])
Этот массив можно использовать далее для различных операций в качестве индекса.
q = b[b>3]
# q == array([4., 5.])
b[b>3] = 0
# b == array([[0., 1.],
# [2., 3.],
# [0., 0.]])
Маску можно использовать для любых массивов имеющих одинаковый shape. Их можно объединить в логические выражение с использованием операторов побитового «и» &
и «или» |
, а также использовать кванторы np.any
и np.all
.
Чтение и запись
Метод | Назначение | Справка |
---|---|---|
np.load | Чтение данных из формата Numpy (Pickle) | load |
np.fromfile | Чтение данных из бинарного файла | fromfile |
np.loadtxt | Чтение данных из текстового файла | loadtxt |
array.save | Сохранение данных в формат Numpy (Pickle) | save |
array.tofile | Сохранение данных в бинарный файл | tofile |
array.savetxt | Запись данных в текстовый файл | savetxt |
</div>
Что еще нужно знать о NumPy
- По NumPy есть подробная официальная документация: https://docs.scipy.org/doc/numpy/reference/index.html
- Для работы с данными содержащими инвалидные значения существует специальный класс
numpy.ma.masked_array
- Два числа с плавающий запятой могут быть равны только чудом, поэтому следует использовать
numpy.isclose
и явно указывать точность. - Классы
np.array
переопределяют вывод на печать. Поэтому сделавprint
вы увидите только часть элементов.