Spec-Zone.ru › NumPy 1.14

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

Класс 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. Это работает очень похоже на __mul__ в Python и другие функции бинарных операций.

  • 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__, можно указать, что ваш класс не поддерживает ufunc, установив __array_ufunc__ = None. Ufunc всегда генерируют 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), и, наконец, вернуть результаты после возможного обратного преобразования. Преимущество этой практики заключается в том, что она гарантирует возможность наличия иерархии подклассов, расширяющих поведение. Подробнее см. Наследование от 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__. Аналогичное преобразование выполняется для входных массивов.

Объекты матриц

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 Возвращает (комплексно) сопряжённую транспонированную self.
    matrix.I Возвращает (мультипликативную) обратную для обратимой self.
    matrix.A Возвращает self как объект ndarray.

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

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

Класс матриц является подклассом 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 Создать отображение памяти на массив, хранящийся в файле binary на диске.
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.14.5/reference/arrays.classes.html

Spec-Zone.ru

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