NumPy, пособие для новичков. Часть 1

NumPy, пособие для новичков. Часть 1

NumPy — это расширение языка Python, добавляющее поддержку больших многомерных массивов и матриц, вместе с большой библиотекой высокоуровневых математических функций для операций с этими массивами.

Первая часть учебника рассказывает об основах работы с NumPy: создании массивов, их атрибутах, базовых операциях, поэлементном применении функций, индексах, срезах, итерировании. Рассматриваются различные манипуляции с преобразованием формы массива, объединение массивов из нескольких и наоборот — разбиение одного на несколько более мелких. В конце мы обсудим поверхностное и глубокое копирование.

Основы

Если вы еще не устанавливали NumPy, то взять его можно здесь. Используемая версия Python — 2.6.

Основным объектом NumPy является однородный многомерный массив. Это таблица элементов (обычно чисел), всех одного типа, индексированных последовательностями натуральных чисел.

Под «многомерностью» массива мы понимаем то, что у него может быть несколько измерений или осей. Поскольку слово «измерение» является неоднозначным, вместо него мы чаще будем использовать слова «ось» (axis) и «оси» (axes). Число осей называется рангом (rank).

Например, координаты точки в трехмерном пространстве [1, 2, 1] это массив ранга 1 у него есть только одна ось. Длина этой оси — 3. Другой пример, массив

представляет массив ранга 2 (то есть это двухмерный массив). Длина первого измерения (оси) — 2, длина второй оси — 3. Для получения дополнительной информации смотрите глоссарий Numpy.

Класс многомерных массивов называется ndarray . Заметим, что это не то же самое, что класс array стандартной библиотеки Python, который используется только для одномерных массивов. Наиболее важные атрибуты объектов ndarray :

ndarray.ndim — число осей (измерений) массива. Как уже было сказано, в мире Python число измерений часто называют рангом.

ndarray.shape — размеры массива, его форма. Это кортеж натуральных чисел, показывающий длину массива по каждой оси. Для матрицы из n строк и m столбов, shape будет (n,m) . Число элементов кортежа shape равно рангу массива, то есть ndim .

ndarray.size — число всех элементов массива. Равно произведению всех элементов атрибута shape .

ndarray.dtype — объект, описывающий тип элементов массива. Можно определить dtype , используя стандартные типы данных Python. NumPy здесь предоставляет целый букет возможностей, например: bool_, character, int_, int8, int16, int32, int64, float_, float8, float16, float32, float64, complex_, complex64, object_ .

ndarray.itemsize — размер каждого элемента массива в байтах. Например, для массива из элементов типа float64 значение itemsize равно 8 (=64/8), а для complex32 этот атрибут равен 4 (=32/8).

ndarray.data — буфер, содержащий фактические элементы массива. Обычно нам не будет нужно использовать этот атрибут, потому как мы будем обращаться к элементам массива с помощью индексов.

Пример
  • a.shape это (2,5)
  • a.ndim это 2 (что равно длине a.shape )
  • a.size это 10
  • a.dtype.name это int32
  • a.itemsize это 4, что означает, что int32 занимает 4 байта памяти.
Создание массивов

Функция array() трансформирует вложенные последовательности в многомерные массивы. Тип массива зависит от типа элементов исходной последовательности.

Раз у нас есть массив, мы можем взглянуть на его атрибуты:

Тип массива может быть явно указан в момент создания:

Часто встречающаяся ошибка состоит в вызове функции array() с множеством числовых аргументов вместо предполагаемого единственного аргумента в виде списка чисел:

Функция array() не единственная функция для создания массивов. Обычно элементы массива вначале неизвестны, а массив, в котором они будут храниться уже нужен. Поэтому имеется несколько функций для того, чтобы создавать массивы с каким-то исходным содержимым. По умолчанию тип создаваемого массива — float64 .

Функция zeros() создает массив нулей, а функция ones() — массив единиц:

Функция empty() создает массив без его заполнения. Исходное содержимое случайно и зависит от состояния памяти на момент создания массива (то есть от того мусора, что в ней хранится):

Для создания последовательностей чисел, в NumPy имеется функция, аналогичная range() , только вместо списков она возвращает массивы:

При использовании arange() с аргументами типа float , сложно быть уверенным в том, сколько элементов будет получено (из-за ограничения точности чисел с плавающей запятой). Поэтому, в таких случаях обычно лучше использовать функцию linspace() которая вместо шага в качестве одного из аргументов принимает число, равное количеству нужных элементов:

Печать массивов
  • последняя ось печатается слева направо,
  • предпоследняя — сверху вниз,
  • и оставшиеся — также сверху вниз, разделяя пустой строкй.

Если массив слишком большой, чтобы его печатать, NumPy автоматически скрывает центральную часть массива и выводит только его уголки:

Если вам действительно нужно увидеть все, что происходит в большом массиве, выведя его полностью, используйте функцию установки печати set_printoptions() :

Базовые операции

В отличие от матричного подхода, оператор произведения * в массивах NumPy работает также поэлементно. Матричное произведение может быть осуществлено либо функцией dot() , либо созданием объектов матриц, которое будет рассмотрено далее (во второй части пособия).

Некоторые операции делаются «на месте», без создания нового массива.

При работе с массивами разных типов, тип результирующего массива соответствует более общему или более точному типу.

Многие унарные операции, такие как вычисление суммы всех элементов массива, представлены в виде методов класса ndarray .

По умолчанию, эти операции применяются к массиву, как если бы он был списком чисел, независимо от его формы. Однако, указав параметр axis можно применить операцию по указанной оси массива:

Универсальные функции Индексы, срезы, итерации

У многомерных массивов на каждую ось приходится один индекс. Индексы передаются в виде последовательности чисел, разделенных запятыми:

Когда индексов меньше, чем осей, отсутствующие индексы предполагаются дополненными с помощью срезов:

b[i] можно читать как b[i, <столько символов ':', сколько нужно>] . В NumPy это также может быть записано с помощью точек, как b[i, . ] .

  • x[1, 2, . ] эквивалентно x[1, 2, :, :, :] ,
  • x[. , 3] то же самое, что x[:, :, :, :, 3] и
  • x[4, . , 5, :] это x[4, :, :, 5, :] .

Итерирование многомерных массивов начинается с первой оси:

Однако, если нужно перебрать поэлементно весь массив, как если бы он был одномерным, для этого можно использовать атрибут flat :

Манипуляции с формой

Форма массива может быть изменена с помощью различных команд:

Порядок элементов в массиве в результате функции ravel() соответствует обычному «C-стилю», то есть, чем правее индекс, тем он «быстрее изменяется»: за элементом a[0,0] следует a[0,1] . Если одна форма массива была изменена на другую, массив переформировывается также в «C-стиле». В таком порядке NumPy обычно и создает массивы, так что для функции ravel() обычно не требуется копировать аргумент, но если массив был создан из срезов другого массива, копия может потребоваться. Функции ravel() и reshape() также могут работать (при использовании дополнительного аргумента) в FORTRAN-стиле, в котором быстрее изменяется более левый индекс.

Функция reshape() возвращает ее аргумент с измененной формой, в то время как метод resize() изменяет сам массив:

Если при операции такой перестройки один из аргументов задается как -1, то он автоматически рассчитывается в соответствии с остальными заданными:

Объединение массивов

Функция column_stack() объединяет одномерные массивы в качестве столбцов двумерного массива:

Аналогично для строк имеется функция row_stack() . Для массивов с более, чем двумя осями, hstack() объединяет массивы по первым осям, vstack() — по последним, дополнительные аргументы позволяют задать число осей по которым должно произойти объединение.

В сложных случаях, могут быть полезны r_[] и с_[] , позволяющие создавать одномерные массивы, с помощью последовательностей чисел вдоль одной оси. В них также имеется возможность использовать ":" для задания диапазона литералов:

Разделение одного массива на несколько более мелких

Функция vsplit() разбивает массив вдоль вертикальной оси, а array_split() позволяет указать оси, вдоль которых произойдет разбиение.

Копии и представления

При работе с массивами, их данные иногда необходимо копировать в другой массив, а иногда нет. Это часто является источником путаницы среди новичков. Возможно всего три случая:

Вообще никаких копий

Python передает изменяемые объекты как ссылки, поэтому вызовы функций также не создают копий:

Представление или поверхностная копия

Разные объекты массивов могут использовать одни и те же данные. Метод view() создает новый объект массива, являющийся представлением тех же данных.

📎📎📎📎📎📎📎📎📎📎