для чего нужен numpy
NumPy в Python. Часть 1
Предисловие переводчика
Доброго времени суток, Хабр. Запускаю цикл статей, которые являются переводом небольшого мана по numpy, ссылочка. Приятного чтения.
Введение
Установка
Если у вас есть Python(x, y) (Примечание переводчика: Python(x, y), это дистрибутив свободного научного и инженерного программного обеспечения для численных расчётов, анализа и визуализации данных на основе языка программирования Python и большого числа модулей (библиотек)) на платформе Windows, то вы готовы начинать. Если же нет, то после установки python, вам нужно установить пакеты самостоятельно, сначала NumPy потом SciPy. Установка доступна здесь. Следуйте установке на странице, там всё предельно понятно.
Немного дополнительной информации
Сообщество NumPy и SciPy поддерживает онлайн руководство, включающие гайды и туториалы, тут: docs.scipy.org/doc.
Импорт модуля numpy
Есть несколько путей импорта. Стандартный метод это — использовать простое выражение:
Тем не менее, для большого количества вызовов функций numpy, становится утомительно писать numpy.X снова и снова. Вместо этого намного легче сделать это так:
Это выражение позволяет нам получать доступ к numpy объектам используя np.X вместо numpy.X. Также можно импортировать numpy прямо в используемое пространство имен, чтобы вообще не использовать функции через точку, а вызывать их напрямую:
Однако, этот вариант не приветствуется в программировании на python, так как убирает некоторые полезные структуры, которые модуль предоставляет. До конца этого туториала мы будем использовать второй вариант импорта (import numpy as np).
Массивы
Главной особенностью numpy является объект array. Массивы схожи со списками в python, исключая тот факт, что элементы массива должны иметь одинаковый тип данных, как float и int. С массивами можно проводить числовые операции с большим объемом информации в разы быстрее и, главное, намного эффективнее чем со списками.
Создание массива из списка:
Здесь функция array принимает два аргумента: список для конвертации в массив и тип для каждого элемента. Ко всем элементам можно получить доступ и манипулировать ими так же, как вы бы это делали с обычными списками:
Массивы могут быть и многомерными. В отличии от списков можно использовать запятые в скобках. Вот пример двумерного массива (матрица):
Array slicing работает с многомерными массивами аналогично, как и с одномерными, применяя каждый срез, как фильтр для установленного измерения. Используйте «:» в измерении для указывания использования всех элементов этого измерения:
Метод shape возвращает количество строк и столбцов в матрице:
Метод dtype возвращает тип переменных, хранящихся в массиве:
Тут float64, это числовой тип данных в numpy, который используется для хранения вещественных чисел двойной точности. Так же как float в Python.
Метод len возвращает длину первого измерения (оси):
Метод in используется для проверки на наличие элемента в массиве:
Массивы можно переформировать при помощи метода, который задает новый многомерный массив. Следуя следующему примеру, мы переформатируем одномерный массив из десяти элементов во двумерный массив, состоящий из пяти строк и двух столбцов:
Обратите внимание, метод reshape создает новый массив, а не модифицирует оригинальный.
Имейте ввиду, связывание имен в python работает и с массивами. Метод copy используется для создания копии существующего массива в памяти:
Списки можно тоже создавать с массивов:
Можно также переконвертировать массив в бинарную строку (то есть, не human-readable форму). Используйте метод tostring для этого. Метод fromstring работает в для обратного преобразования. Эти операции иногда полезны для сохранения большого количества данных в файлах, которые могут быть считаны в будущем.
Заполнение массива одинаковым значением.
Транспонирование массивов также возможно, при этом создается новый массив:
Многомерный массив можно переконвертировать в одномерный при помощи метода flatten:
Два или больше массивов можно сконкатенировать при помощи метода concatenate:
Если массив не одномерный, можно задать ось, по которой будет происходить соединение. По умолчанию (не задавая значения оси), соединение будет происходить по первому измерению:
В заключении, размерность массива может быть увеличена при использовании константы newaxis в квадратных скобках:
Заметьте, тут каждый массив двумерный; созданный при помощи newaxis имеет размерность один. Метод newaxis подходит для удобного создания надлежаще-мерных массивов в векторной и матричной математике.
На этом у нас конец первой части перевода. Спасибо за внимание.
Руководство по использованию Python-библиотеки NUMPY
Предок NumPy, Numeric, был разработан Джимом Хугунином. Также был создан пакет Numarray с дополнительной функциональностью. В 2005 году Трэвис Олифант выпустил пакет NumPy, добавив особенности Numarray в Numeric. Это проект с исходным кодом, и в его развитии поучаствовало уже много человек.
NumPy или Numerical Python — это библиотека Python, которая предлагает следующее:
Она также предлагает эффективный многомерный контейнер общих данных. С ее помощью можно определять произвольные типы данных. Официальный сайт библиотеки — www.numpy.org
Установка NumPy в Python
Массив NumPy
Это мощный многомерный массив в форме строк и колонок. С помощью библиотеки можно создавать массивы NumPy из вложенного списка Python и получать доступ к его элементам.
Массив NumPy — это не то же самое, что и класс array.array из Стандартной библиотеки Python, который работает только с одномерными массивами.
Одномерный массив NumPy.
Атрибуты массива NumPy
ndarray.ndim
Возвращает количество измерений массива.
Вывод кода сверху будет 2, поскольку «a» — это 2-мерный массив.
ndarray.shape
Возвращает кортеж размера массива, то есть (n,m), где n — это количество строк, а m — количество колонок.
Вывод кода — (2,3), то есть 2 строки и 3 колонки.
ndarray.size
Возвращает общее количество элементов в массиве.
Вывод — 6, потому что 2 х 3.
ndarray.dtype
Возвращает объект, описывающий тип элементов в массиве.
Вывод — «int32», поскольку это 32-битное целое число.
Можно явно определить тип данных массива NumPy.
ndarray.itemsize
Возвращает размер каждого элемента в массиве в байтах.
Вывод — 4, потому что 32/8.
ndarray.data
Возвращает буфер с актуальными элементами массива. Это альтернативный способ получения доступа к элементам через их индексы.
Этот код вернет список элементов.
ndarray.sum()
Функция вернет сумму все элементов ndarray.
ndarray.min()
Функция вернет элемент с минимальным значением из ndarray.
ndarray.max()
Функция вернет элемент с максимальным значением из ndarray.
Функции NumPy
numpy.zeroes()
numpy.zeros((rows, columns), dtype)
Эта функция создаст массив numpy с заданным количеством измерений, где каждый элемент будет равняться 0. Если dtype не указан, по умолчанию будет использоваться dtype.
Код вернет массив numpy 3×3, где каждый элемент равен 0.
numpy.ones()
numpy.ones((rows,columns), dtype)
Эта функция создаст массив numpy с заданным количеством измерений, где каждый элемент будет равняться 1. Если dtype не указан, по умолчанию будет использоваться dtype.
Код вернет массив numpy 3 x 3, где каждый элемент равен 1.
numpy.empty()
numpy.empty((rows,columns))
Эта функция создаст массив, содержимое которого будет случайным — оно зависит от состояния памяти.
Код вернет массив numpy 3×3, где каждый элемент будет случайным.
Вывод этого кода — [5 9 13 17 21]
numpy.sin()
numpy.sin(numpy.ndarray)
Этот код вернет синус параметра.
numpy.reshape()
numpy.reshape(dimensions)
Эта функция используется для изменения количества измерений массива numpy. От количества аргументов в reshape зависит, сколько измерений будет в массиве numpy.
Вывод этого года — 2-мерный массив 3×3.
numpy.random.random()
numpy.random.random((rows, column))
Эта функция возвращает массив с заданным количеством измерений, где каждый элемент генерируется случайным образом.
Этот код вернет ndarray 2×2.
numpy.exp()
numpy.exp(numpy.ndarray)
Функция вернет ndarray с экспоненциальной величиной каждого элемента.
numpy.sqrt()
numpy.sqrt(numpy.ndarray)
Эта функция вернет ndarray с квадратным корнем каждого элемента.
Этот код вернет значение 4.
Базовые операции NumPy
Базовые операции с массивом NumPy
Выводы
Из этого материала вы узнали, что такое numpy и как его устанавливать, познакомились с массивов numpy, атрибутами и операциями массива numpy, а также базовыми операциями numpy.
NumPy, пособие для новичков. Часть 1
NumPy — это расширение языка Python, добавляющее поддержку больших многомерных массивов и матриц, вместе с большой библиотекой высокоуровневых математических функций для операций с этими массивами.
Первая часть учебника рассказывает об основах работы с NumPy: создании массивов, их атрибутах, базовых операциях, поэлементном применении функций, индексах, срезах, итерировании. Рассматриваются различные манипуляции с преобразованием формы массива, объединение массивов из нескольких и наоборот — разбиение одного на несколько более мелких. В конце мы обсудим поверхностное и глубокое копирование.
Основы
Если вы еще не устанавливали NumPy, то взять его можно здесь. Используемая версия Python — 2.6.
Основным объектом NumPy является однородный многомерный массив. Это таблица элементов (обычно чисел), всех одного типа, индексированных последовательностями натуральных чисел.
Под «многомерностью» массива мы понимаем то, что у него может быть несколько измерений или осей. Поскольку слово «измерение» является неоднозначным, вместо него мы чаще будем использовать слова «ось» (axis) и «оси» (axes). Число осей называется рангом (rank).
Например, координаты точки в трехмерном пространстве [1, 2, 1] это массив ранга 1 у него есть только одна ось. Длина этой оси — 3. Другой пример, массив
представляет массив ранга 2 (то есть это двухмерный массив). Длина первого измерения (оси) — 2, длина второй оси — 3. Для получения дополнительной информации смотрите глоссарий Numpy.
ndarray.ndim — число осей (измерений) массива. Как уже было сказано, в мире Python число измерений часто называют рангом.
ndarray.itemsize — размер каждого элемента массива в байтах. Например, для массива из элементов типа float64 значение itemsize равно 8 (=64/8), а для complex32 этот атрибут равен 4 (=32/8).
ndarray.data — буфер, содержащий фактические элементы массива. Обычно нам не будет нужно использовать этот атрибут, потому как мы будем обращаться к элементам массива с помощью индексов.
Пример
Создание массивов
Функция array() трансформирует вложенные последовательности в многомерные массивы. Тип массива зависит от типа элементов исходной последовательности.
Раз у нас есть массив, мы можем взглянуть на его атрибуты:
Тип массива может быть явно указан в момент создания:
Часто встречающаяся ошибка состоит в вызове функции array() с множеством числовых аргументов вместо предполагаемого единственного аргумента в виде списка чисел:
Функция zeros() создает массив нулей, а функция ones() — массив единиц:
Функция empty() создает массив без его заполнения. Исходное содержимое случайно и зависит от состояния памяти на момент создания массива (то есть от того мусора, что в ней хранится):
Печать массивов
Если массив слишком большой, чтобы его печатать, NumPy автоматически скрывает центральную часть массива и выводит только его уголки:
Если вам действительно нужно увидеть все, что происходит в большом массиве, выведя его полностью, используйте функцию установки печати set_printoptions() :
Copy Source | Copy HTML
>>> set_printoptions(threshold=nan)
Базовые операции
Некоторые операции делаются «на месте», без создания нового массива.
При работе с массивами разных типов, тип результирующего массива соответствует более общему или более точному типу.
По умолчанию, эти операции применяются к массиву, как если бы он был списком чисел, независимо от его формы. Однако, указав параметр axis можно применить операцию по указанной оси массива:
Универсальные функции
Индексы, срезы, итерации
У многомерных массивов на каждую ось приходится один индекс. Индексы передаются в виде последовательности чисел, разделенных запятыми:
Когда индексов меньше, чем осей, отсутствующие индексы предполагаются дополненными с помощью срезов:
Итерирование многомерных массивов начинается с первой оси:
Copy Source | Copy HTML
>>> for row in b:
. print row
.
[ 0 1 2 3 ]
[ 10 11 12 13 ]
[ 20 21 22 23 ]
[ 30 31 32 33 ]
[ 40 41 42 43 ]
Однако, если нужно перебрать поэлементно весь массив, как если бы он был одномерным, для этого можно использовать атрибут flat :
Copy Source | Copy HTML
>>> for element in b.flat:
. print element,
.
0 1 2 3 10 11 12 13 20 21 22 23 30 31 32 33 40 41 42 43
Манипуляции с формой
Форма массива может быть изменена с помощью различных команд:
Функция reshape() возвращает ее аргумент с измененной формой, в то время как метод resize() изменяет сам массив:
Объединение массивов
Функция column_stack() объединяет одномерные массивы в качестве столбцов двумерного массива:
Разделение одного массива на несколько более мелких
Функция vsplit() разбивает массив вдоль вертикальной оси, а array_split() позволяет указать оси, вдоль которых произойдет разбиение.
Копии и представления
При работе с массивами, их данные иногда необходимо копировать в другой массив, а иногда нет. Это часто является источником путаницы среди новичков. Возможно всего три случая:
Вообще никаких копий
Python передает изменяемые объекты как ссылки, поэтому вызовы функций также не создают копий:
Представление или поверхностная копия
Разные объекты массивов могут использовать одни и те же данные. Метод view() создает новый объект массива, являющийся представлением тех же данных.
Срез массива это представление:
NumPy
NumPy — это библиотека Python, которую применяют для математических вычислений: начиная с базовых функций и заканчивая линейной алгеброй. Полное название библиотеки — Numerical Python extensions, или «Числовые расширения Python».
У этой библиотеки есть несколько важных особенностей, которые сделали ее популярным инструментом. Во-первых, исходный ее код в свободном доступе хранится на GitHub, поэтому NumPy называют open-source модулем для Python.
Во-вторых, библиотека написана на языках C и Fortran. Это компилируемые языки (языки программирования, текст которых преобразуется в машинный код — набор инструкций для конкретного типа процессора. Преобразование происходит с помощью специальной программы-компилятора, благодаря нему вычисления на компилируемых языках происходят быстрее), на которых вычисления производятся гораздо быстрее и эффективнее, чем на интерпретируемых языках (языки программирования, которые не заточены под конкретный тип процессора и могут быть запущены на разных типах устройств). К этим языкам относится и сам Python.
Где используется NumPy
Как работает NumPy
Для начала разберемся в устройстве массивов, которые обрабатывает NumPy. Рассмотрим однородный двумерный массив. Он выглядит как простая таблица — две оси значений и ячейки внутри (элементы массива). Если появится третья ось, то массив станет трехмерным. Важное условие — все элементы должны иметь единый тип данных, например только целые числа.
Конечно, кроме двумерных массивов, библиотека NumPy обрабатывает и другие, с различным количеством осей. Эту вариативность обозначают числом N, как любую переменную в математической задаче. Поэтому обычно говорят, что NumPy работает с N-мерными массивами данных.
Читайте также: Кому и зачем нужен Python?
С этими данными NumPy производит вычисления, используя математические функции, генераторы случайных чисел, линейные уравнения или преобразования Фурье. Например, можно решить систему уравнений методом linalg.solve:
Как и сам Python, библиотека NumPy отличается простотой в изучении и использовании. Для начала работы достаточно освоить концепцию массивов. Например, в базовых арифметических вычислениях есть способ обработки массивов, который называют трансляцией или broadcasting.
Если в массиве величины указаны в милях, а результат нужно получить в километрах, можно умножить его на простое число 1,6 (скалярную величину). NumPy принимает самостоятельное решение умножить на заданное число каждый элемент в массиве, и пользователю не приходится прописывать для этого отдельную команду.
Подробной документации NumPy на русском языке до сих пор нет, а в рунете можно найти только краткие выжимки, в которых упущены многие моменты. Поэтому, чтобы стать специалистом высокого уровня в Data Science или Machine Learning, придется подтянуть английский. Начать можно с информации на официальном сайте.
Python для аналитики данных
Вы сможете автоматизировать сбор и анализ данных о ваших конкурентах, пользователях и потенциальных партнерах с помощью Python. Дополнительная скидка 5% по промокоду BLOG.
Как загрузить библиотеку?
Для загрузки NumPy просто введите в командной строке: import numpy as np. Не удивляйтесь, если библиотека окажется установленной, ведь модуль NumPy входит в состав множества пакетов и других библиотек.
Конечно, можно написать просто import numpy, ошибки в этом не будет. Но np — это общепринятое название, которое стало правилом и упростило процесс написания кода, поэтому, один раз прописав import numpy as np, в последующих строках можно использовать np вместо numpy.
Нескучный туториал по NumPy
Меня зовут Вячеслав, я хронический математик и уже несколько лет не использую циклы при работе с массивами…
Ровно с тех пор, как открыл для себя векторные операции в NumPy. Я хочу познакомить вас с функциями NumPy, которые чаще всего использую для обработки массивов данных и изображений. В конце статьи я покажу, как можно использовать инструментарий NumPy, чтобы выполнить свертку изображений без итераций (= очень быстро).
Что такое NumPy?
Это библиотека с открытым исходным кодом, некогда отделившаяся от проекта SciPy. NumPy является наследником Numeric и NumArray. Основан NumPy на библиотеке LAPAC, которая написана на Fortran. Не-python альтернативой для NumPy является Matlab.
В силу того, что NumPy базируется на Fortran это быстрая библиотека. А в силу того, что поддерживает векторные операции с многомерными массивами — крайне удобная.
Кроме базового варианта (многомерные массивы в базовом варианте) NumPy включает в себя набор пакетов для решения специализированных задач, например:
Создание массива
Создать массив можно несколькими способами:
Либо взять размеры уже существующего массива:
По умолчанию from = 0, step = 1, поэтому возможен вариант с одним параметром, интерпретируемым как To:
Либо с двумя — как From и To:
Обратите внимание, что в методе №3 размеры массива передавались в качестве одного параметра (кортеж размеров). Вторым параметром в способах №3 и №4 можно указать желаемый тип элементов массива:
Используя метод astype, можно привести массив к другому типу. В качестве параметра указывается желаемый тип:
Все доступные типы можно найти в словаре sctypes:
Доступ к элементам, срезы
Доступ к элементам массива осуществляется по целочисленным индексами, начинается отсчет с 0:
Если представить многомерный массив как систему вложенных одномерных массивов (линейный массив, элементы которого могут быть линейными массивами), становится очевидной возможность получать доступ к подмассивам с использованием неполного набора индексов:
С учетом этой парадигмы, можем переписать пример доступа к одному элементу:
При использовании неполного набора индексов, недостающие индексы неявно заменяются списком всех возможных индексов вдоль соответствующей оси. Сделать это явным образом можно, поставив «:». Предыдущий пример с одним индексом можно переписать в следующем виде:
«Пропустить» индекс можно вдоль любой оси или осей, если за «пропущенной» осью последуют оси с индексацией, то «:» обязательно:
Индексы могут принимать отрицательные целые значения. В этом случае отсчет ведется от конца массива:
Можно использовать не одиночные индексы, а списки индексов вдоль каждой оси:
Либо диапазоны индексов в виде «From:To:Step». Такая конструкция называется срезом. Выбираются все элементы по списку индексов начиная с индекса From включительно, до индекса To не включая с шагом Step:
Шаг индекса имеет значение по умолчанию 1 и может быть пропущен:
Значения From и To тоже имеют дефолтные значения: 0 и размер массива по оси индексации соответственно:
Если вы хотите использовать From и To по умолчанию (все индексы по данной оси) а шаг отличный от 1, то вам необходимо использовать две пары двоеточий, чтобы интерпретатор смог идентифицировать единственный параметр как Step. Следующий код «разворачивает» массив вдоль второй оси, а вдоль первой не меняет:
Как видите, через B мы изменили данные в A. Вот почему в реальных задачах важно использовать копии. Пример выше должен был бы выглядеть так:
В NumPy также реализована возможность доступа ко множеству элементов массива через булев индексный массив. Индексный массив должен совпадать по форме с индексируемым.
Как видите, такая конструкция возвращает плоский массив, состоящий из элементов индексируемого массива, соответствующих истинным индексам. Однако, если мы используем такой доступ к элементам массива для изменения их значений, то форма массива сохранится:
Над индексирующими булевыми массивами определены логические операции logical_and, logical_or и logical_not выполняющие логические операции И, ИЛИ и НЕ поэлементно:
logical_and и logical_or принимают 2 операнда, logical_not — один. Можно использовать операторы &, | и
для выполнения И, ИЛИ и НЕ соответственно с любым количеством операндов:
Что эквивалентно применению только I1.
Получить индексирующий логический массив, соответсвующий по форме массиву значений можно, записав логическое условие с именем массива в качестве операнда. Булево значение индекса будет рассчитано как истинность выражения для соответствующего элемента массива.
Найдем индексирующий массив I элементов, которые больше, чем 3, а элементы со значениями меньше чем 2 и больше 4 — обнулим:
Форма массива и ее изменение
Многомерный массив можно представить как одномерный массив максимальной длины, нарезанный на фрагменты по длине самой последней оси и уложенный слоями по осям, начиная с последних.
Для наглядности рассмотрим пример:
В этом примере мы из одномерного массива длиной 24 элемента сформировали 2 новых массива. Массив B, размером 4 на 6. Если посмотреть на порядок значений, то видно, что вдоль второго измерения идут цепочки последовательных значений.
В массиве C, размером 4 на 3 на 2, непрерывные значения идут вдоль последней оси. Вдоль второй оси идут последовательно блоки, объединение которых дало бы в результате строки вдоль второй оси массива B.
А учитывая, что мы не делали копии, становится понятно, что это разные формы преставления одного и того же массива данных. Поэтому можно легко и быстро менять форму массива, не изменяя самих данных.
Чтобы узнать размерность массива (количество осей), можно использовать поле ndim (число), а чтобы узнать размер вдоль каждой оси — shape (кортеж). Размерность можно также узнать и по длине shape. Чтобы узнать полное количество элементов в массиве можно воспользоваться значением size:
Обратите внимание, что ndim и shape — это атрибуты, а не методы!
Чтобы увидеть массив одномерным, можно воспользоваться функцией ravel:
Чтобы поменять размеры вдоль осей или размерность используется метод reshape:
Важно, чтобы количество элементов сохранилось. Иначе возникнет ошибка:
Можно reshape использовать вместо ravel:
Рассмотрим практическое применение некоторых возможностей для обработки изображений. В качестве объекта исследования будем использовать фотографию:
Попробуем ее загрузить и визуализировать средствами Python. Для этого нам понадобятся OpenCV и Matplotlib:
Результат будет такой:
Обратите внимание на строку загрузки:
OpenCV работает с изображениями в формате BGR, а нам привычен RGB. Мы меняем порядок байтов вдоль оси цвета без обращения к функциям OpenCV, используя конструкцию
«[:, :, ::-1]».
Уменьшим изображение в 2 раза по каждой оси. Наше изображение имеет четные размеры по осям, соответственно, может быть уменьшено без интерполяции:
Поменяв форму массива, мы получили 2 новые оси, по 2 значения в каждой, им соответствуют кадры, составленные из нечетных и четных строк и столбцов исходного изображения.
Низкое качество свзано с использованием Matplotlib, за то там видны размеры по осям. На самом деле, качество уменьшенного изображения такое:
Перестановка осей и траспонирование
В кроме изменения формы массива при неизменном порядке единиц данных, часто встречается необходимость изменить порядок следования осей, что естественным образом повлечет перестановки блоков данных.
Примером такого преобразования может быть транспонирование матрицы: взаимозамена строк и столбцов.
В этом примере для транспонирования матрицы A использовалась конструкция A.T. Оператор транспонирования инвертирует порядок осей. Рассмотрим еще один пример с тремя осями:
У этой короткой записи есть более длинный аналог: np.transpose(A). Это более универсальный инструмент для замены порядка осей. Вторым параметром можно задать кортеж номеров осей исходного массива, определяющий порядок их положения в результирующем массиве.
Для примера переставим первые две оси изображения. Картинка должна перевернуться, но цветовую ось оставим без изменения:
Для этого примера можно было применить другой инструмент swapaxes. Этот метод переставляет местами две оси, указанные в параметрах. Пример выше можно было реализовать так:
Объединение массивов
Объединяемые массивы должны иметь одинаковое количество осей. Объединять массивы можно с образованием новой оси, либо вдоль уже существующей.
Для объединения с образованием новой оси исходные массивы должны иметь одинаковые размеры вдоль всех осей:
Как видно из примера, массивы-операнды стали подмассивами нового объекта и выстроились вдоль новой оси, которая стоит самой первой по порядку.
Для объединения массивов вдоль существующей оси, они должны иметь одинаковый размер по всем осям, кроме выбранной для объединения, а по ней могут иметь произвольные размеры:
Для объединения по первой или второй оси можно использовать методы vstack и hstack соответсвенно. Покажем это на примере изображений. vstack объединяет изображения одинаковой ширины по высоте, а hsstack объединяет одинаковые по высоте картинки в одно широкое:
Обратите внимание на то, что во всех примерах этого раздела объединяемые массивы передаются одним параметром (кортежем). Количество операндов может быть любым, а не обязательно только 2.
Также обратите внимание на то, что происходит с памятью, при объединении массивов:
Так как создается новый объект, данные в него копируются из исходных массивов, поэтому изменения в новых данных не влияют на исходные.
Клонирование данных
Оператор np.repeat(A, n) вернет одномерный массив с элементами массива A, каждый из которых будет повторен n раз.
После этого преобразования, можно перестроить геометрию массива и собрать повторяющиеся данные в одну ось:
Этот вариант отличается от объединения массива с самим собой оператором stack только положением оси, вдоль которой стоят одинаковые данные. В примере выше это последняя ось, если использовать stack — первая:
Как бы ни было выполнено клонирование данных, следующим шагом можно переместить ось, вдоль которой стоят одинаковые значения, в любую позицию с системе осей:
Если же мы хотим «растянуть» какую либо ось, используя повторение элементов, то ось с одинаковыми значениями надо поставить после растягиваемой (используя transpose), а затем объединить эти две оси (используя reshape). Рассмотрим пример с растяжением изображения вдоль вертикальной оси за счет дублирования строк:
Математические операции над элементами массива
Если A и B массивы одинакового размера, то их можно складывать, умножать, вычитать, делить и возводить в степень. Эти операции выполняются поэлементно, результирующий массив будет совпадать по геометрии с исходными массивами, а каждый его элемент будет результатом выполнения соответствующей операции над парой элементов из исходных массивов:
Можно выполнить любую операцию из приведенных выше над массивом и числом. В этом случае операция также выполнится над каждым из элементов массива:
Учитывая, что многомерный массив можно рассматривать как плоский массив (первая ось), элементы которого — массивы (остальные оси), возможно выполнение рассматриваемых операций над массивами A и B в случае, когда геометрия B совпадает с геометрией подмассивов A при фиксированном значении по первой оси. Иными словами, при совпадающем количестве осей и размерах A[i] и B. Этом случае каждый из массивов A[i] и B будут операндами для операций, определенных над массивами.
В этом примере массив B подвергается операции с каждой строкой массива A. При необходимости умножения/деления/сложения/вычитания/возведения степень подмассивов вдоль другой оси, необходимо использовать транспонирование, чтобы поставить нужную ось на место первой, а затем вернуть ее на свое место. Рассмотри пример выше, но с умножением на вектор B столбцов массива A:
Для более сложных функций (например, для тригонометрических, экспоненты, логарифма, преобразования между градусами и радианами, модуля, корня квадратного и.д.) в NumPy есть реализация. Рассмотрим на примере экспоненты и логарифма:
С полным списком математических операций в NumPy можно ознакомиться тут.
Матричное умножение
Описанная выше операция произведения массивов выполняется поэлементно. А при необходимости выполнения операций по правилам линейной алгебры над массивами как над тензорами можно воспользоваться методом dot(A, B). В зависимости от вида операндов, функция выполнит:
Рассмотрим примеры со скалярами и векторами:
С тензорами посмотрим только на то, как меняется размер геометрия результирующего массива:
Для выполнения произведения тензоров с использованием других осей, вместо определенных для dot можно воспользоваться tensordot с явным указанием осей:
Мы явно указали, используем третью ось первого массива и вторую — второго (размеры по этим осям должны совпадать).
Агрегаторы
Агрегаторы — это методы NumPy позволяющие заменять данные интегральными характеристиками вдоль некоторых осей. Например, можно посчитать среднее значение, максимальное, минимальное, вариацию или еще какую-то характеристику вдоль какой-либо оси или осей и сформировать из этих данных новый массив. Форма нового массива будет содержать все оси исходного массива, кроме тех, вдоль которых подсчитывался агрегатор.
Для примера, сформируем массив со случайными значениями. Затем найдем минимальное, максимальное и среднее значение в его столбцах:
При таком использовании mean и average выглядят синонимами. Но эти функции обладают разным набором дополнительных параметров. У нах разные возможности по маскированию и взвешиванию усредняемых данных.
Можно подсчитать интегральные характеристики и по нескольким осям:
В этом примере рассмотрена еще одна интегральная характеристика sum — сумма.
Список агрегаторов выглядит примерно так:
Если не указать оси, то по умолчанию все рассматриваемые характеристики считаются по всему массиву. В этом случае argmin и argmax тоже корректно отработают и найдут индекс максимального или минимального элемента так, как буд-то все данные в массиве вытянуты вдоль одной оси командой ravel().
Еще следует отметить, агрегирующие методы определены не только как методы модуля NumPy, но и для самих массивов: запись np.aggregator(A, axes) эквивалентна записи A.aggregator(axes), где под aggregator подразумевается одна из рассмотренных выше функций, а под axes — индексы осей.
Вместо заключения — пример
Давайте построим алгоритм линейной низкочастотной фильтрации изображения.
Для начала загрузим зашумленное изображение.
Рассмотрим фрагмент изображения, чтобы увидеть шум:
Фильтровать изображение будем с использованием гауссова фильтра. Но вместо выполнения свертки непосредственно (с итерированием), применим взвешенное усреднение срезов изображения, сдвинутых относительно друг друга:
Применим эту функцию к нашему изображению единожды, дважды и трижды:
Получаем следующие результаты:
при однократном применении фильтра;
Видно, что с повышением количества проходов фильтра снижается уровень шума. Но при этом снижается и четкость изображения. Это известная проблема линейных фильтров. Но наш метод денойзинга изображения не претендует на оптимальность: это лишь демонстрация возможностей NumPy реализации свертки без итераций.
Теперь давайте посмотрим, сверткам с какими ядрами эквивалентна наша фильтрация. Для этого подвергнем аналогичным преобразованиям одиночный единичный импульс и визуализируем. На самом деле импульс будет не единичным, а равным по амплитуде 255, так как само смешивание оптимизировано под целочисленные данные. Но это не мешает оценить общий вид ядер:
Мы рассмотрели далеко не полный набор возможностей NumPy, надеюсь, этого было достаточно для демонстрации всей мощи и красоты этого инструмента!