Стандартные подклассы массивов
В NumPy ndarray является встроенным типом Python «нового стиля». Поэтому его можно наследоваться от (в Python или C), если необходимо. Таким образом, он может послужить основой для многих полезных классов. Часто выбор между наследованием от объекта массива или использованием ядра массива как внутренней части нового класса — сложное решение, которое часто сводится к предпочтениям. NumPy предоставляет несколько инструментов для упрощения взаимодействия вашего нового объекта с другими объектами массивов, и поэтому этот выбор может в конечном итоге оказаться не столь значительным. Один из способов упростить вопрос — спросить себя, может ли интересующий вас объект быть представлен как единый массив, или он действительно требует два или более массивов в своей основе.
Обратите внимание, что asarray всегда возвращает базовый массив ndarray. Если вы уверены, что ваш способ использования объекта массива может обрабатывать любой подкласс ndarray, то asanyarray может использоваться для более чистого распространения подклассов через вашу подпрограмму. В теории подкласс может переопределить любой аспект массива, и поэтому, при строгих правилах, asanyarray вряд ли будет полезен. Однако большинство подклассов объекта массива не будут переопределять определённые аспекты объекта массива, такие как интерфейс буфера или атрибуты массива. Однако одним важным примером, почему ваша подпрограмма может не обрабатывать произвольный подкласс массива, является то, что матрицы переопределяют оператор «*» для матричного умножения, а не для поэлементного умножения.
Специальные атрибуты и методы
См. также
NumPy предоставляет несколько крючков, которые классы могут настроить:
-
class.__array_ufunc__(ufunc, method, *inputs, **kwargs) -
Новое в версии 1.13.
Примечание
API является временным, т.е. мы пока не гарантируем обратную совместимость.
Любой класс, являющийся или не являющийся подклассом ndarray, может определить этот метод или установить его в
Noneдля переопределения поведения унарных функций 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.
Примечание
Если класс определяет метод
__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. Однако существует шесть важных отличий матричных объектов, которые могут привести к неожиданным результатам, когда вы используете матрицы, но ожидаете, что они будут действовать как массивы:
- Матричные объекты могут быть созданы с помощью строковой нотации, чтобы разрешить синтаксис в стиле Matlab, где пробелы отделяют столбцы, а точки с запятой (';') отделяют строки.
- Матричные объекты всегда двумерные. Это имеет далеко идущие последствия, так как m.ravel() по-прежнему двумерный (с 1 в первом измерении), а выбор элементов возвращает двумерные объекты, поэтому поведение последовательности фундаментально отличается от массивов.
- Матричные объекты переопределяют умножение для матричного умножения. Убедитесь, что вы понимаете это для функций, которые вы хотите получать матрицы. Особенно с учетом того, что asanyarray(m) возвращает матрицу, когда m является матрицей.
- Матричные объекты переопределяют возведение в степень для возведения матрицы в степень. То же предупреждение об использовании степени внутри функции, которая использует asanyarray(...), чтобы получить массив, справедливо и для этого факта.
- По умолчанию __array_priority__ матричных объектов равен 10.0, и поэтому смешанные операции с ndarray всегда производят матрицы.
-
Матрицы имеют специальные атрибуты, которые упрощают вычисления. Это
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)
См. также
Примечание
Класс 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[, …]) | Стандартный класс контейнера для простого множественного наследования. |
Итераторы массивов
Итераторы — мощная концепция для обработки массивов. По существу, итераторы реализуют обобщенную циклическую конструкцию. Если myiter — это объект итератора, то код Python:
for val in myiter:
...
some code involving val
...
вызывает val = myiter.next() многократно, пока StopIteration не будет поднята итератором. Есть несколько способов итерирования по массиву, которые могут быть полезными: стандартное итерирование, итерирование по плоскому массиву и -мерное перечисление.
Стандартное итерирование
Стандартный итератор объекта ndarray — это стандартный Python-итератор типа последовательности. Таким образом, когда сам объект массива используется как итератор. Стандартное поведение эквивалентно:
for i in range(arr.shape[0]):
val = arr[i]
Этот стандартный итератор выбирает подмассив размерности из массива. Это может быть полезной конструкцией для определения рекурсивных алгоритмов. Чтобы перебрать весь массив, требуется
вложенных циклов.
>>> 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-мерному массиву. |
Как уже упоминалось, атрибут flat объектов ndarray возвращает итератор, который будет перебирать весь массив в порядке, непрерывном со стороны С.
>>> 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. Этот объект принимает объекты в качестве входных данных и возвращает итератор, который возвращает кортежи, содержащие каждый элемент входной последовательности в широковещательном результате.
>>> 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.15.4/reference/arrays.classes.html