Стандартные подклассы массивов
Примечание
Наследование от numpy.ndarray возможно, но если вашей целью является создание массива с изменённым поведением, как в dask массивах для распределённых вычислений или cupy массивах для вычислений на GPU, наследование не рекомендуется. Вместо этого рекомендуется использовать механизм диспетчеризации NumPy механизм диспетчеризации.
Класс ndarray можно наследовать (в Python или C), если это необходимо. Поэтому он может послужить основой для многих полезных классов. Часто выбор между наследованием от объекта массива или использованием ядра массива как внутренней части нового класса является сложным решением и может зависеть просто от предпочтений. NumPy предоставляет несколько инструментов, упрощающих взаимодействие вашего нового объекта с другими объектами массивов, поэтому этот выбор в конечном итоге может не иметь большого значения. Один из способов упростить вопрос — спросить себя, можно ли заменить интересующий объект одним массивом, или же для его реализации необходимо два или более массивов.
Обратите внимание, что asarray всегда возвращает массив базового класса ndarray. Если вы уверены, что ваш объект массива может обрабатывать любой подкласс ndarray, то asanyarray можно использовать для более чистого распространения подклассов через вашу подпрограмму. В принципе, подкласс может переопределять любой аспект массива, и поэтому, при строгих правилах, asanyarray редко будет полезен. Однако большинство подклассов объекта массива не будут переопределять некоторые аспекты объекта массива, такие как интерфейс буфера или атрибуты массива. Важным примером, однако, того, почему ваша подпрограмма может не обработать произвольный подкласс массива, является то, что матрицы переопределяют оператор “*” на матричное умножение, а не на поэлементное.
Специальные атрибуты и методы
См. также
NumPy предоставляет несколько крючков, которые классы могут настроить:
-
class.__array_ufunc__(ufunc, method, *inputs, **kwargs) -
Новое в версии 1.13.
Любой класс, являющийся или не являющийся подклассом ndarray, может определить этот метод или установить его в значение
None, чтобы переопределить поведение функций NumPy ufuncs. Это работает очень похоже на__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, но может быть относительно легко переписан как (набор) обобщенных функций Ufuncs. То же самое может произойти с функциями, такими как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для представления того, что массив имеет единицы «метры», но при этом не хочет взаимодействовать с массивами через функции ufuncs или каким-либо другим способом. Это можно сделать, установив__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, кажется очень неожиданным и, следовательно, путающим, так как тогда подкласс вообще не будет работать с функциями ufuncs). -
ndarrayопределяет свою собственную__array_ufunc__, которая вычисляет ufunc, если у аргументов нет переопределений, и возвращаетNotImplementedв противном случае. Это может быть полезно для подклассов, для которых__array_ufunc__преобразует любые экземпляры своего собственного класса вndarray: тогда он может передать их своему суперклассу с помощьюsuper().__array_ufunc__(*inputs, **kwargs), и, наконец, вернуть результаты после возможного преобразования обратно. Преимущество этого подхода заключается в том, что он обеспечивает возможность создания иерархии подклассов, которые расширяют поведение. Подробности см. в Наследование от ndarray.
Примечание
Если класс определяет метод
__array_ufunc__, это отключает механизм__array_wrap__,__array_prepare__,__array_priority__, описанный ниже для функций ufuncs (который может быть в конечном итоге устаревшим).
-
class.__array_function__(func, types, args, kwargs) -
Добавлена в версии 1.16.
Примечание
- В NumPy 1.17 протокол включён по умолчанию, но может быть отключён с помощью
NUMPY_EXPERIMENTAL_ARRAY_FUNCTION=0. - В NumPy 1.16 необходимо установить переменную окружения
NUMPY_EXPERIMENTAL_ARRAY_FUNCTION=1перед импортом NumPy, чтобы использовать переопределения функций NumPy. - В конечном счёте, ожидается, что
__array_function__будет всегда включён.
-
func— произвольная вызываемая функция, экспонируемая общедоступным API NumPy, которая была вызвана в видеfunc(*args, **kwargs). -
types— коллекция уникальных типов аргументов из исходного вызова функции NumPy, которые реализуют__array_function__. - Кортеж
argsи словарьkwargsнапрямую передаются из исходного вызова.
Для удобства разработчиков
__array_function__реализаций,typesпредоставляет все типы аргументов с атрибутом'__array_function__'. Это позволяет разработчикам быстро определять случаи, когда они должны делегировать__array_function__реализации другим аргументам. Реализации не должны полагаться на порядок итерацииtypes.Большинство реализаций
__array_function__начинаются с двух проверок:- Является ли данная функция той, которую мы знаем, как перегрузить?
- Все ли аргументы являются типами, которые мы знаем, как обработать?
Если эти условия выполняются,
__array_function__должен вернуть результат вызова своей реализации дляfunc(*args, **kwargs). В противном случае он должен вернуть значение-сентинельNotImplemented, указывающее, что функция не реализована для этих типов.Нет общих требований к возвращаемому значению из
__array_function__, хотя большинство разумных реализаций, вероятно, должны вернуть массив(ы) с тем же типом, что и один из аргументов функции.Также может быть удобно определить пользовательские декораторы (
implementsниже) для регистрации реализаций__array_function__.HANDLED_FUNCTIONS = {} class MyArray: def __array_function__(self, func, types, args, kwargs): if func not in HANDLED_FUNCTIONS: return NotImplemented # Note: this allows subclasses that don't override # __array_function__ to handle MyArray objects if not all(issubclass(t, MyArray) for t in types): return NotImplemented return HANDLED_FUNCTIONS[func](*args, **kwargs) def implements(numpy_function): """Register an __array_function__ implementation for MyArray objects.""" def decorator(func): HANDLED_FUNCTIONS[numpy_function] = func return func return decorator @implements(np.concatenate) def concatenate(arrays, axis=0, out=None): ... # implementation of concatenate for MyArray objects @implements(np.broadcast_to) def broadcast_to(array, shape): ... # implementation of broadcast_to for MyArray objectsОбратите внимание, что реализации
__array_function__не обязаны включать все соответствующие необязательные аргументы функции NumPy (например,broadcast_toвыше опускает неважный аргументsubok). Необязательные аргументы передаются в__array_function__только в том случае, если они были явно использованы в вызове функции NumPy.Так же, как и в случае с встроенными специальными методами, такими как
__add__, правильно написанные методы__array_function__должны всегда возвращатьNotImplementedпри обнаружении неизвестного типа. В противном случае будет невозможно правильно переопределить функции NumPy из другого объекта, если операция также включает один из ваших объектов.По большей части правила диспетчеризации с
__array_function__соответствуют правилам для__array_ufunc__. В частности:- NumPy соберет реализации
__array_function__от всех указанных входных данных и вызовет их в порядке: подклассы перед суперклассами, а в противном случае — слева направо. Обратите внимание, что в некоторых крайних случаях, связанных с подклассами, это немного отличается от текущего поведения Python. - Реализации
__array_function__указывают, что они могут обработать операцию, вернув любое значение, отличное отNotImplemented. - Если все методы
__array_function__возвращаютNotImplemented, NumPy выведетTypeError.
Если методы
__array_function__не существуют, NumPy по умолчанию вызовет свою собственную реализацию, предназначенную для использования с массивами NumPy. Этот случай возникает, например, когда все аргументы, похожие на массивы, являются числами Python или списками. (У массивов NumPy есть метод__array_function__, указанный ниже, но он всегда возвращаетNotImplemented, если какой-либо аргумент, кроме подкласса массива NumPy, реализует__array_function__.)Отклонение от текущего поведения
__array_ufunc__заключается в том, что NumPy вызовет__array_function__только для первого аргумента каждого уникального типа. Это соответствует правилу Python для вызова отражённых методов правилу вызова отражённых методов, и это гарантирует, что проверка перегрузок имеет приемлемую производительность даже при большом количестве перегруженных аргументов. - В NumPy 1.17 протокол включён по умолчанию, но может быть отключён с помощью
-
class.__array_finalize__(obj) -
Этот метод вызывается всякий раз, когда система внутри выделяет новый массив из obj, где obj — подкласс (подтип)
ndarray. Он может использоваться для изменения атрибутов self после построения (например, для обеспечения 2-мерной матрицы) или для обновления метаданных от «родителя». Подклассы наследуют реализацию этого метода по умолчанию, которая ничего не делает.
-
class.__array_prepare__(array, context=None) -
В начале каждого ufunc этот метод вызывается для входного объекта с наивысшим приоритетом массива или выходного объекта, если он был указан. Выходной массив передаётся, и всё, что возвращается, передаётся в ufunc. Подклассы наследуют реализацию этого метода по умолчанию, которая просто возвращает выходной массив без изменений. Подклассы могут использовать этот метод для преобразования выходного массива в экземпляр подкласса и обновления метаданных перед возвращением массива в ufunc для вычисления.
Примечание
Для ufuncs, есть надежда на то, что этот метод в конечном итоге будет устаревшим в пользу
__array_ufunc__.
-
class.__array_wrap__(array, context=None) -
В конце каждого ufunc этот метод вызывается для входного объекта с наивысшим приоритетом массива или выходного объекта, если он был указан. Вычисленный ufunc массив передаётся, и всё, что возвращается, передаётся пользователю. Подклассы наследуют реализацию этого метода по умолчанию, которая преобразует массив в новый экземпляр класса объекта. Подклассы могут использовать этот метод для преобразования выходного массива в экземпляр подкласса и обновления метаданных перед возвращением массива пользователю.
Примечание
Для ufuncs, есть надежда на то, что этот метод в конечном итоге будет устаревшим в пользу
__array_ufunc__.
-
class.__array_priority__ -
Значение этого атрибута используется для определения типа объекта, который должен возвращаться в ситуациях, когда есть более чем одна возможность для Python-типа возвращаемого объекта. Подклассы наследуют значение атрибута по умолчанию 0.0.
Примечание
Для ufuncs, есть надежда на то, что этот метод в конечном итоге будет устаревшим в пользу
__array_ufunc__.
-
class.__array__([dtype]) -
Если класс (подкласс ndarray или нет), имеющий метод
__array__, используется как выходной объект ufunc, результаты будут записаны в объект, возвращённый__array__. Аналогичное преобразование выполняется для входных массивов.
Объекты матриц
Примечание
Сильно рекомендуется не использовать подкласс матриц. Как описано ниже, это затрудняет написание функций, которые последовательно обрабатывают матрицы и обычные массивы. В настоящее время они в основном используются для взаимодействия с scipy.sparse. Однако, мы надеемся предоставить альтернативу для этого использования и в конечном итоге удалить подкласс matrix.
matrix объекты наследуют от ndarray и поэтому имеют те же атрибуты и методы, что и ndarrays. Однако существует шесть важных различий объектов матриц, которые могут привести к неожиданным результатам, когда вы используете матрицы, но ожидаете, что они будут действовать как массивы:
- Объекты матриц могут быть созданы с использованием строковой нотации, что позволяет использовать синтаксис Matlab, где пробелы отделяют столбцы, а точки с запятой (';') отделяют строки.
- Объекты матриц всегда двумерные. Это имеет далеко идущие последствия, так как m.ravel() все еще двумерный (с 1 в первом измерении), а выбор элементов возвращает двумерные объекты, так что поведение последовательностей принципиально отличается от массивов.
- Объекты матриц переопределяют умножение, чтобы оно было матричным умножением. Убедитесь, что вы понимаете это для функций, которые могут принимать матрицы. Особенно с учетом того, что asanyarray(m) возвращает матрицу, когда m является матрицей.
- Объекты матриц переопределяют возведение в степень, чтобы оно было возведением матрицы в степень. То же предупреждение о использовании возведения в степень внутри функции, которая использует asanyarray(...), чтобы получить объект массива, справедливо и для этого факта.
- Значение __array_priority__ по умолчанию для объектов матриц равно 10.0, и поэтому смешанные операции с ndarrays всегда производят матрицы.
-
У матриц есть специальные атрибуты, которые упрощают вычисления. Это:
matrix.TВозвращает транспонированную матрицу. matrix.HВозвращает (комплексно) сопряженную транспонированную матрицу. matrix.IВозвращает (мультипликативное) обратное значение обратимой матрицы. 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 | Создать отображение в памяти массива, хранящегося в бинарном файле на диске. |
memmap.flush(self) | Записать любые изменения в массиве в файл на диске. |
Пример:
>>> 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 также может быть создан с помощью конструктора 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 не будет поднят итератором. Существует несколько способов итерирования по массиву, которые могут быть полезны: стандартное итерирование, плоское итерирование и -мерное перечисление.
Стандартное итерирование
Стандартный итератор объекта ndarray — это стандартный Python-итератор типа последовательности. Таким образом, при использовании самого объекта массива в качестве итератора. Стандартное поведение эквивалентно:
for i in range(arr.shape[0]):
val = arr[i]
Этот стандартный итератор выбирает подмассив размерности из массива. Это может быть полезной конструкцией для определения рекурсивных алгоритмов. Для цикла по всему массиву требуются
цикла 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. |
Как упоминалось ранее, атрибут flat объектов ndarray возвращает итератор, который пройдёт по всему массиву в стиле contiguous-порядка 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. Этот объект принимает объекты в качестве входных данных и возвращает итератор, который возвращает кортежи, предоставляющие каждый из элементов входных последовательностей в результирующем широковещательном формате.
>>> 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.17.0/reference/arrays.classes.html