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() создает новый объект массива, являющийся представлением тех же данных.