====== Числовые данные в Python ====== Встроенные средства Python не слишком хороши для работы с числовыми данными, поэтому для этого существуют отдельные модули. Наиболее важной из них является модуль [[http://www.numpy.org/|NumPy]]pip, высокоэффективные методы для работы с числовыми массивам. ====== 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. ]) # точки от 0 до 5 с шагом 1 a = np.arange(0,5,1) # a == array([0, 1, 2, 3, 4])
===== Многомерные массивы ===== Класс ''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.]]) # Изменение порядка осей b = np.moveaxis(b,0,-1) # b == array([[0., 2., 4.], # [1., 3., 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'', ...).
===== Конкатенация ===== b = np.linspace(0,5,6).reshape((3,2)) # b == array([[ 0., 1.], # [ 2., 3.], # [ 4., 5.]]) # Конкатенация по строкам d = np.vstack((b,b)) # d == array([[0., 1.], # [2., 3.], # [4., 5.], # [0., 1.], # [2., 3.], # [4., 5.]]) # Конкатенация по столбцам d = np.hstack((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.save('file.npy', M)'' | Сохранение данных в формат Numpy | [[https://numpy.org/doc/stable/reference/generated/numpy.save.html|save]] | | ''M = np.load('file.npy')'' | Чтение данных из формата Numpy | [[https://numpy.org/doc/stable/reference/generated/numpy.load.html|load]] | | ''np.savetxt('file.txt',M)'' | Запись данных в текстовый файл | [[https://numpy.org/doc/stable/reference/generated/numpy.savetxt.html#numpy.savetxt|savetxt]] | | ''M = np.loadtxt('file.txt')'' | Чтение данных из текстового файла | [[ https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html|loadtxt]] | | ''M.tofile('file.dat')'' | Сохранение данных в бинарный файл | [[https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tofile.html|tofile]] | | ''M = np.fromfile('file.dat')'' | Чтение данных из бинарного файла | [[https://numpy.org/doc/stable/reference/generated/numpy.fromfile.html|fromfile]] |
===== Что еще нужно знать о NumPy ===== * По NumPy есть подробная официальная документация: [[https://docs.scipy.org/doc/numpy/reference/index.html]] * Для работы с данными содержащими инвалидные значения существует специальный класс ''numpy.ma.masked_array'' * Два числа с плавающий запятой могут быть равны только чудом, поэтому следует использовать ''numpy.isclose'' и явно указывать точность. * Классы ''np.array'' переопределяют вывод на печать. Поэтому сделав ''print'' вы увидите только часть элементов.