Spec-Zone.ru › NumPy 1.16

Стандартные подклассы массивов

Класс ndarray в NumPy является «классом нового стиля» встроенного типа Python. Поэтому его можно унаследовать (в Python или C), если это необходимо. Следовательно, он может служить основой для многих полезных классов. Часто выбор между наследованием от объекта массива или использованием базового компонента массива как внутренней части нового класса является сложным решением и может быть просто вопросом выбора. NumPy предоставляет несколько инструментов для упрощения взаимодействия вашего нового объекта с другими объектами массивов, поэтому конечный выбор может не иметь большого значения. Один из способов упростить вопрос — спросить себя, может ли интересующий вас объект быть представлен как один массив, или он действительно требует двух или более массивов в своей основе.

Обратите внимание, что asarray всегда возвращает базовый класс ndarray. Если вы уверены, что ваш способ использования объекта массива может обрабатывать любой подкласс ndarray, то asanyarray может быть использован для более чистого распространения подклассов через вашу подпрограмму. В принципе, подкласс может переопределить любой аспект массива, и поэтому, при строгих правилах, asanyarray будет редко полезен. Однако большинство подклассов объекта массива не будут переопределять определённые аспекты объекта массива, такие как интерфейс буфера или атрибуты массива. Однако важным примером, почему ваша подпрограмма может не справиться с произвольным подклассом массива, является то, что матрицы переопределяют оператор «*» на матричное умножение, а не на поэлементное.

Специальные атрибуты и методы

См. также

Наследование от ndarray

NumPy предоставляет несколько крючков, которые классы могут настроить:

class.__array_ufunc__(ufunc, method, *inputs, **kwargs)

Новое в версии 1.13.

Примечание

API является временным, т.е. мы пока не гарантируем обратную совместимость.

Любой класс, являющийся или не являющийся подклассом ndarray, может определить этот метод или установить его в None, чтобы переопределить поведение ufunc NumPy. Это работает очень похоже на операторы Python __mul__ и другие бинарные операции.

  • ufunc — это объект ufunc, который был вызван.
  • method — строка, указывающая, какой метод Ufunc был вызван (один из "__call__", "reduce", "reduceat", "accumulate", "outer", "inner").
  • inputs — кортеж входных аргументов для вызываемого ufunc.
  • kwargs — словарь, содержащий необязательные входные аргументы ufunc. Если указаны, все аргументы out, как позиционные, так и именованные, передаются в виде tuple в kwargs. Подробности см. в разделе Универсальные функции (ufunc).

Метод должен вернуть либо результат операции, либо NotImplemented, если запрашиваемая операция не реализована.

Если у одного из входных или выходных аргументов есть метод __array_ufunc__, он выполняется вместо ufunc. Если несколько аргументов реализуют __array_ufunc__, они выполняются в порядке: подклассы перед суперклассами, входные перед выходными, в противном случае слева направо. Первая функция, возвращающая что-то, кроме NotImplemented, определяет результат. Если все операции __array_ufunc__ возвращают NotImplemented, генерируется исключение TypeError.

Примечание

Мы намерены повторно реализовать функции NumPy в виде (обобщённых) Ufunc, в этом случае у них появится возможность переопределения методом __array_ufunc__ . Типичный пример — matmul, которая в настоящее время не является Ufunc, но её можно относительно легко переписать в виде (набора) обобщённых Ufunc. То же самое может произойти с функциями, такими как median, min, и argsort.

Как и в случае с некоторыми другими специальными методами в Python, такими как __hash__ и __iter__, можно указать, что ваш класс не поддерживает ufuncs, установив __array_ufunc__ = None. Ufuncs всегда генерируют TypeError при вызове на объекте, который устанавливает __array_ufunc__ = None.

Наличие __array_ufunc__ также влияет на то, как ndarray обрабатывает бинарные операции, такие как arr + obj и arr < obj, когда arr — это ndarray, а obj — это экземпляр пользовательского класса. Есть два варианта. Если obj.__array_ufunc__ присутствует и не равно None, тогда ndarray.__add__ и аналогичные функции делегируют обработку ufunc, что означает, что arr + obj становится np.add(arr, obj), а затем add вызывает obj.__array_ufunc__. Это полезно, если вы хотите определить объект, который ведёт себя как массив.

В противном случае, если obj.__array_ufunc__ установлено в None, то в качестве исключительного случая специальные методы, такие как ndarray.__add__, заметят это и безусловно сгенерируют TypeError. Это полезно, если вы хотите создать объекты, которые взаимодействуют с массивами через бинарные операции, но сами по себе не являются массивами. Например, система обработки единиц может иметь объект m, представляющий единицу «метры», и желает поддерживать синтаксис arr * m для обозначения того, что массив имеет единицы «метры», но не желает иначе взаимодействовать с массивами через ufunc или иным образом. Это можно сделать, установив __array_ufunc__ = None и определив методы __mul__ и __rmul__. (Обратите внимание, что это означает, что написать __array_ufunc__ , который всегда возвращает NotImplemented , не совсем то же самое, что установить __array_ufunc__ = None: в первом случае arr + obj сгенерирует TypeError, а во втором случае можно определить метод __radd__ для предотвращения этого.)

Вышесказанное не относится к операторам на месте, для которых ndarray никогда не возвращает NotImplemented. Следовательно, arr += obj всегда приведёт к TypeError. Это связано с тем, что для массивов операции на месте не могут быть универсально заменены простой обратной операцией. (Например, по умолчанию arr += obj будет переведено в arr = arr + obj, то есть arr будет заменено, что противоречит ожидаемому поведению операций с массивами на месте.)

Примечание

Если вы определяете __array_ufunc__:

  • Если вы не являетесь подклассом ndarray, мы рекомендуем вашему классу определить специальные методы, такие как __add__ и __lt__ , которые делегируют обработку ufunc так же, как делает ndarray. Простой способ сделать это — наследоваться от NDArrayOperatorsMixin.
  • Если вы наследуете от ndarray, мы рекомендуем разместить всю логику переопределения в __array_ufunc__ , а не переопределять также специальные методы. Это гарантирует, что иерархия классов определяется только в одном месте, а не отдельно механизмом ufunc и правилами бинарных операций (которые отдают предпочтение специальным методам подклассов; альтернативный способ принудительной иерархии в одном месте — установить __array_ufunc__ в None, что кажется очень неожиданным и, следовательно, запутанным, так как подкласс больше не будет работать с ufunc).
  • ndarray определяет свой собственный __array_ufunc__, который вычисляет ufunc, если у аргументов нет переопределений, и возвращает NotImplemented в противном случае. Это может быть полезно для подклассов, для которых __array_ufunc__ преобразует любые экземпляры своего собственного класса в ndarray: он может передать их своему суперклассу с помощью super().__array_ufunc__(*inputs, **kwargs), а затем вернуть результаты после возможного обратного преобразования. Преимущество этого подхода заключается в том, что он гарантирует возможность создания иерархии подклассов, которые расширяют поведение. Подробнее см. Subclassing ndarray.
END_OF_DOCUMENT_MARKER

Примечание

Если класс определяет метод __array_ufunc__, это отключает механизм __array_wrap__, __array_prepare__, __array_priority__, описанный ниже для ufunc (который может быть в конечном итоге устаревшим).

class.__array_finalize__(obj)

Этот метод вызывается всякий раз, когда система внутренне выделяет новый массив из obj, где obj является подклассом (подтипом) ndarray. Он может быть использован для изменения атрибутов self после создания (например, для обеспечения 2-мерной матрицы) или для обновления метаданных из «родителя». Подклассы наследуют по умолчанию реализацию этого метода, которая ничего не делает.

class.__array_prepare__(array, context=None)

В начале каждого ufunc этот метод вызывается на объекте входа с наивысшим приоритетом массива или на объекте вывода, если он был указан. Массив вывода передаётся, и всё, что возвращается, передаётся ufunc. Подклассы наследуют по умолчанию реализацию этого метода, которая просто возвращает массив вывода без изменений. Подклассы могут использовать этот метод для преобразования выходного массива в экземпляр подкласса и обновления метаданных перед возвращением массива в ufunc для вычисления.

Примечание

Для ufunc, в будущем планируется сделать этот метод устаревшим в пользу __array_ufunc__.

class.__array_wrap__(array, context=None)

В конце каждого ufunc этот метод вызывается на объекте входа с наивысшим приоритетом массива или на объекте вывода, если он был указан. Вычисленный ufunc массив передаётся, и всё, что возвращается, передаётся пользователю. Подклассы наследуют по умолчанию реализацию этого метода, которая преобразует массив в новый экземпляр класса объекта. Подклассы могут использовать этот метод для преобразования выходного массива в экземпляр подкласса и обновления метаданных перед возвращением массива пользователю.

Примечание

Для ufunc, в будущем планируется сделать этот метод устаревшим в пользу __array_ufunc__.

class.__array_priority__

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

Примечание

Для ufunc, в будущем планируется сделать этот метод устаревшим в пользу __array_ufunc__.

class.__array__([dtype])

Если класс (подкласс ndarray или нет), имеющий метод __array__, используется в качестве объекта вывода ufunc, результаты будут записаны в объект, возвращаемый __array__. Аналогичное преобразование выполняется для входных массивов.

Матричные объекты

Примечание

Сильно рекомендуется не использовать подкласс матриц. Как описано ниже, это затрудняет написание функций, которые последовательно обрабатывают матрицы и обычные массивы. В настоящее время они в основном используются для взаимодействия с scipy.sparse. В будущем мы надеемся предоставить альтернативу для этого использования и в конечном итоге удалить подкласс matrix.

matrix объекты наследуют от ndarray и, следовательно, обладают теми же атрибутами и методами, что и ndarray. Однако существует шесть важных отличий матричных объектов, которые могут привести к неожиданным результатам, когда вы используете матрицы, но ожидаете, что они будут действовать как массивы:

  1. Матричные объекты могут быть созданы с помощью строковой нотации, чтобы разрешить синтаксис в стиле Matlab, где пробелы отделяют столбцы, а точки с запятой (';') отделяют строки.
  2. Матричные объекты всегда двумерные. Это имеет далеко идущие последствия, так как m.ravel() по-прежнему двумерный (с 1 в первом измерении), а выбор элементов возвращает двумерные объекты, поэтому поведение последовательности фундаментально отличается от массивов.
  3. Матричные объекты переопределяют умножение для матричного умножения. Убедитесь, что вы понимаете это для функций, которые вы хотите получать матрицы. Особенно с учетом того, что asanyarray(m) возвращает матрицу, когда m является матрицей.
  4. Матричные объекты переопределяют возведение в степень для возведения матрицы в степень. То же предупреждение об использовании степени внутри функции, которая использует asanyarray(...), чтобы получить массив, справедливо и для этого факта.
  5. По умолчанию __array_priority__ матричных объектов равен 10.0, и поэтому смешанные операции с ndarray всегда производят матрицы.
  6. Матрицы имеют специальные атрибуты, которые упрощают вычисления. Это

    matrix.T Возвращает транспонированную матрицу.
    matrix.H Возвращает (комплексно) сопряжённую транспонированную матрицу.
    matrix.I Возвращает (мультипликативное) обратное значение для обратимой self.
    matrix.A Возвращает self как объект ndarray.

Предупреждение

Матричные объекты переопределяют умножение, '*', и возведение в степень, '**', для матричного умножения и матричной степени соответственно. Если ваша подпрограмма может принимать подклассы, и вы не конвертируете их в массивы базового класса, то вы должны использовать ufuncs multiply и power, чтобы быть уверенными, что вы выполняете правильную операцию для всех входных данных.

Класс matrix является подклассом ndarray в Python и может быть использован в качестве справочника для создания собственного подкласса ndarray. Матрицы могут быть созданы из других матриц, строк и всего, что может быть преобразовано в ndarray. Имя “mat” является псевдонимом для “matrix” в NumPy.

matrix(data[, dtype, copy])
asmatrix(data[, dtype]) Интерпретировать входные данные как матрицу.
bmat(obj[, ldict, gdict]) Построить матричный объект из строки, вложенной последовательности или массива.

Пример 1: Создание матрицы из строки

>>> a=mat('1 2 3; 4 5 3')
>>> print (a*a.T).I
[[ 0.2924 -0.1345]
 [-0.1345  0.0819]]

Пример 2: Создание матрицы из вложенной последовательности

>>> mat([[1,5,10],[1.0,3,4j]])
matrix([[  1.+0.j,   5.+0.j,  10.+0.j],
        [  1.+0.j,   3.+0.j,   0.+4.j]])

Пример 3: Создание матрицы из массива

>>> mat(random.rand(3,3)).T
matrix([[ 0.7699,  0.7922,  0.3294],
        [ 0.2792,  0.0101,  0.9219],
        [ 0.3398,  0.7571,  0.8197]])

Массивы с отображением в памяти

Файлы с отображением в памяти полезны для чтения и/или изменения небольших сегментов большого файла с регулярной структурой, не загружая весь файл в память. Простой подкласс ndarray использует файл с отображением в памяти для буфера данных массива. Для небольших файлов накладные расходы на загрузку всего файла в память обычно не существенны, однако для больших файлов использование отображения в памяти может сэкономить значительные ресурсы.

Массивы с отображением в памяти имеют один дополнительный метод (кроме тех, которые они наследуют от ndarray): .flush(), который пользователь должен вызывать вручную, чтобы убедиться, что любые изменения в массиве действительно записываются на диск.

memmap Создать отображение в памяти на массив, хранящийся в бинарном файле на диске.
memmap.flush() Записать любые изменения в массиве в файл на диске.

Пример:

>>> a = memmap('newfile.dat', dtype=float, mode='w+', shape=1000)
>>> a[10] = 10.0
>>> a[30] = 30.0
>>> del a
>>> b = fromfile('newfile.dat', dtype=float)
>>> print b[10], b[30]
10.0 30.0
>>> a = memmap('newfile.dat', dtype=float)
>>> print a[10], a[30]
10.0 30.0

Массивы символов (numpy.char)

См. также

Создание массивов символов (numpy.char)

Примечание

Класс chararray существует для обратной совместимости с Numarray, его не рекомендуется использовать в новых разработках. Начиная с numpy 1.4, если требуются массивы строк, рекомендуется использовать массивы типа dtype object_, string_ или unicode_, и использовать свободные функции в модуле numpy.char для быстрых векторизованных строковых операций.

Это расширенные массивы типа string_ или unicode_ Эти массивы наследуются от ndarray, но специально определяют операции +, *, и % на основе (векторного) элемента по элементу. Эти операции недоступны для стандартного ndarray символьного типа. Кроме того, chararray имеет все стандартные string (и unicode) методы, выполняющие их на основе элемента по элементу. Возможно, самый простой способ создать chararray — использовать self.view(chararray), где self — ndarray типа str или unicode. Однако chararray также можно создать, используя конструктор numpy.chararray или функцию numpy.char.array:

chararray(shape[, itemsize, unicode, …]) Предоставляет удобный вид на массивы значений строк и unicode.
core.defchararray.array(obj[, itemsize, …]) Создать chararray.

Другое различие со стандартным ndarray типа str заключается в том, что chararray наследует функцию, введенную Numarray, что пробелы в конце любого элемента массива будут игнорироваться при получении элемента и операциях сравнения.

Массивы записей (numpy.rec)

См. также

Создание массивов записей (numpy.rec), Процедуры типов данных, Объекты типов данных (dtype).

NumPy предоставляет класс recarray, который позволяет получать доступ к полям структурированного массива как к атрибутам, и соответствующий скалярный объект типа данных record.

recarray Создает ndarray, который позволяет получать доступ к полям с помощью атрибутов.
record Скалярный тип данных, который позволяет получать доступ к полям как к атрибутам.

Маскированные массивы (numpy.ma)

См. также

Маскированные массивы

Стандартный контейнерный класс

Для обратной совместимости и в качестве стандартного «контейнерного» класса класс UserArray из Numeric перенесен в NumPy и переименован в numpy.lib.user_array.container. Контейнерный класс — это класс Python, атрибут self.array которого — ndarray. Наследование с множественным наследованием, вероятно, проще с помощью numpy.lib.user_array.container, чем с самим ndarray, и поэтому оно включено по умолчанию. Здесь он не документирован подробно, кроме упоминания его существования, потому что рекомендуется использовать класс ndarray напрямую, если это возможно.

numpy.lib.user_array.container(data[, …]) Стандартный контейнерный класс для простого множественного наследования.

Итераторы массивов

Итераторы — мощная концепция для обработки массивов. По сути, итераторы реализуют обобщенный цикл for. Если myiter — объект итератора, то код Python:

for val in myiter:
    ...
    some code involving val
    ...

вызывает val = myiter.next() многократно, пока StopIteration не будет поднят итератором. Существует несколько способов итерирования по массиву, которые могут быть полезны: стандартное итерирование, итерирование по плоскому массиву и N-мерное перечисление.

Стандартное итерирование

Стандартный итератор объекта ndarray — это стандартный Python-итератор типа последовательности. Таким образом, когда сам объект массива используется как итератор. Стандартное поведение эквивалентно:

for i in range(arr.shape[0]):
    val = arr[i]

Этот стандартный итератор выбирает подмассив размерности N-1 из массива. Это может быть полезным инструментом для определения рекурсивных алгоритмов. Для перебора всего массива необходимо N циклов for.

>>> a = arange(24).reshape(3,2,4)+10
>>> for val in a:
...     print 'item:', val
item: [[10 11 12 13]
 [14 15 16 17]]
item: [[18 19 20 21]
 [22 23 24 25]]
item: [[26 27 28 29]
 [30 31 32 33]]

Итерирование по плоскому массиву

ndarray.flat Итератор по 1-D массиву.

Как уже упоминалось, атрибут flat объектов ndarray возвращает итератор, который будет проходить по всему массиву в порядке, контигуальном для C-стиля.

>>> for i, val in enumerate(a.flat):
...     if i%5 == 0: print i, val
0 10
5 15
10 20
15 25
20 30

Здесь я использовал встроенный итератор enumerate для возврата индекса итератора, а также значения.

N-мерное перечисление

ndenumerate(arr) Многомерный итератор индексов.

Иногда может быть полезно получить N-мерный индекс во время итерирования. Итератор ndenumerate может этого добиться.

>>> for i, val in ndenumerate(a):
...     if sum(i)%5 == 0: print i, val
(0, 0, 0) 10
(1, 1, 3) 25
(2, 0, 3) 29
(2, 1, 2) 32

Итератор для векторизации

broadcast Создать объект, имитирующий векторизацию.

Общая концепция векторизации также доступна из Python с помощью итератора broadcast. Этот объект принимает N объекты в качестве входных данных и возвращает итератор, который возвращает кортежи, предоставляющие каждый элемент входной последовательности в результатах векторизованного преобразования.

>>> for val in broadcast([[1,0],[2,3]],[0,1]):
...     print val
(1, 0)
(0, 1)
(2, 0)
(3, 1)

© 2005–2019 NumPy Developers
Licensed under the 3-clause BSD License.
https://docs.scipy.org/doc/numpy-1.16.1/reference/arrays.classes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API