注意
numpy.ndarray
可以对a 进行子类化,但是如果您的目标是创建具有经过修改的行为的数组(用于分布式计算的dask数组和用于基于GPU的计算的cupy数组),则不建议进行子类化。相反,建议使用numpy的
调度机制。
ndarray
如果需要,可以从(在Python或C中)继承。因此,它可以为许多有用的类奠定基础。通常是对数组对象进行子类化还是将核心数组组件用作新类的内部部分是一个困难的决定,并且可能只是选择问题。NumPy有几个工具可以简化新对象与其他数组对象的交互方式,因此最终选择可能并不重要。简化问题的一种方法是询问自己是否可以将感兴趣的对象替换为单个数组,或者它的核心确实需要两个或多个数组。
请注意,asarray
始终返回基类ndarray。如果您确信对数组对象的使用可以处理ndarray的任何子类,则asanyarray
可以用于允许子类通过子例程更清晰地传播。原则上,子类可以重新定义数组的任何方面,因此,在严格的指导下,它asanyarray
几乎没有用处。但是,数组对象的大多数子类不会重新定义数组对象的某些方面,例如缓冲区接口或数组的属性。但是,为什么子例程可能无法处理数组的任意子类的一个重要示例是,矩阵将“ *”运算符重新定义为矩阵乘法,而不是逐元素乘法。
也可以看看
NumPy提供了几个类可以自定义的钩子:
class.
__array_ufunc__
(ufunc,method,* inputs,** kwargs )¶1.13版中的新功能。
任何类,无论是否为ndarray子类,都可以定义此方法或将其设置为None,以覆盖NumPy的ufunc的行为。这与Python __mul__
和其他二进制操作例程非常相似。
ufunc是被调用的ufunc对象。
方法是指示Ufunc方法被称为一个字符串(之一"__call__"
,"reduce"
,"reduceat"
,
"accumulate"
,"outer"
,"inner"
)。
输入是的输入参数的元组ufunc
。
kwargs是一个字典,其中包含ufunc的可选输入参数。如果给定,则所有out
位置和关键字参数都作为tuple
in kwargs传递。有关详细信息,请参见通用函数(ufunc)中的讨论。
该方法应返回操作的结果,或者
NotImplemented
未执行所请求的操作。
如果输入或输出参数之一具有__array_ufunc__
方法,则将执行该方法而不是 ufunc。如果实现多个参数__array_ufunc__
,则按以下顺序尝试:在超类之前的子类,在输出之前的输入,否则从左到右。第一个例程返回除NotImplemented
确定结果以外的其他
值。如果所有
__array_ufunc__
操作都返回NotImplemented
,
TypeError
则引发a。
注意
我们打算将numpy函数重新实现为(通用)Ufunc,在这种情况下,有可能被该__array_ufunc__
方法覆盖。最主要的候选者是
matmul
,目前不是Ufunc,但可以相对容易地重写为(一组)广义Ufunc。同样可以用功能,如发生median
,
amin
和argsort
。
像Python中其他一些特殊的方法,如__hash__
和
__iter__
,有可能表明你的类并没有
被设定支持ufuncs 。当调用set对象时,
Ufuncs始终会升高
。__array_ufunc__ = None
TypeError
__array_ufunc__ = None
的存在__array_ufunc__
还会影响如何
ndarray
处理二进制操作(例如,何时是和是自定义类的实例)。有两种可能性。如果
存在并且不是None,则
和朋友将委派给ufunc机制,这意味着变为,然后
调用。如果要定义一个像数组一样的对象,这很有用。arr + obj
arr
< obj
arr
ndarray
obj
obj.__array_ufunc__
ndarray.__add__
arr + obj
np.add(arr, obj)
add
obj.__array_ufunc__
或者,如果obj.__array_ufunc__
将其设置为None,则在特殊情况下,特殊方法如ndarray.__add__
会注意到这一点而无条件地引发TypeError
。如果要创建通过二进制操作与数组进行交互但本身不是数组的对象,这将很有用。例如,单位处理系统可能有一个对象m
代表“米”单位,并希望支持表示该数组具有“米”单位的语法,但又不想通过ufunc或其他方式与数组进行交互。这可以通过设置和定义
和方法来完成。(请注意,这意味着编写始终返回的an
和set 并不完全相同:在前一种情况下,arr * m
__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__
像ndarray一样委托给ufuncs。一种简单的方法是从继承NDArrayOperatorsMixin
。
如果您子类化ndarray
,我们建议您放入所有重写逻辑,__array_ufunc__
而不要重写特殊方法。这样可以确保类层次结构仅在一个地方确定,而不是由ufunc机制和二进制操作规则(它优先于子类的特殊方法;仅强制一个地方的层次结构,将其设置__array_ufunc__
为None)的另一种方法来确定。 ,这看起来非常出乎意料,因此令人困惑,因为子类无法与ufunc一起使用)。
ndarray
定义自己的__array_ufunc__
,如果没有参数覆盖,则对ufunc求值,NotImplemented
否则返回
。这对于__array_ufunc__
将其自身类的任何实例转换为的子类可能是有用的ndarray
:然后可以使用将它们传递给其超类,并在可能的反向转换之后最终返回结果。这种做法的优点在于,它确保可以具有扩展行为的子类层次结构。有关详细信息,请参见
子类化ndarray。super().__array_ufunc__(*inputs, **kwargs)
注意
如果一个类定义了__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
是NumPy的公共API公开的任意可调用对象,其调用形式为。func(*args, **kwargs)
types
是
实现的原始NumPy函数调用中唯一参数类型的集合__array_function__
。
元组args
和字典kwargs
直接从原始调用传递。
为了方便__array_function__
实现者,请types
为所有参数类型提供一个'__array_function__'
属性。这使实现者可以快速确定应遵循__array_function__
其他论点实现的情况。实现不应依赖的迭代顺序types
。
大多数的实现__array_function__
将以两项检查开始:
给定的函数是我们知道如何重载的吗?
是否所有的参数都是我们知道如何处理的类型?
如果满足这些条件,__array_function__
则应从调用其实现返回结果。否则,它应该返回sentinel值,指示该功能不是由这些类型实现的。func(*args, **kwargs)
NotImplemented
__array_function__
尽管大多数明智的实现都应该返回与函数的参数之一具有相同类型的数组,但是对from的返回值没有一般要求
。
定义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 调用反射方法的规则,并且即使在有大量重载参数的情况下,也可以确保检查重载具有可接受的性能。
class.
__array_finalize__
(obj )¶每当系统内部从obj分配新数组时,都会调用此方法,其中obj是的子类(子类型)
ndarray
。它可以用于
在构造后更改self的属性(例如,以确保二维矩阵),或用于更新“父级”的元信息。子类继承此方法的默认实现,该实现不执行任何操作。
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__
。
注意
强烈建议不要使用矩阵子类。如下所述,这使得编写处理矩阵和常规数组的函数非常困难。目前,它们主要用于与进行交互scipy.sparse
。我们希望为此提供一种替代方法,并最终删除matrix
子类。
matrix
对象从ndarray继承,因此它们具有相同的ndarray属性和方法。但是,矩阵对象有六个重要区别,当您使用矩阵但希望它们像数组一样工作时,可能会导致意外结果:
可以使用字符串符号创建矩阵对象,以允许使用Matlab样式的语法,其中空格分隔列,分号(';')分隔行。
矩阵对象始终是二维的。这具有深远的意义,因为m.ravel()仍然是二维的(在第一维中为1),并且项选择返回二维对象,因此序列行为与数组本质上不同。
矩阵对象优先于乘法,成为矩阵乘法。请确保您了解一些可能要接收矩阵的函数。特别是考虑到当m是矩阵时asanyarray(m)返回矩阵的事实。
矩阵对象优先于幂而将矩阵提升为幂。对于使用asanyarray(…)获取数组对象的函数内部使用电源的相同警告也适用于此事实。
矩阵对象的默认__array_priority__是10.0,因此,与ndarrays混合使用的操作总是会产生矩阵。
矩阵具有特殊的属性,使计算更容易。这些是
返回矩阵的转置。 |
|
返回self的(复杂)共轭转置。 |
|
返回可逆self的(乘法)逆。 |
|
将self作为 |
警告
矩阵对象优先于乘法(*)和幂(**),分别是矩阵乘法和矩阵幂。如果您的子例程可以接受子类,并且您没有转换为基类数组,则必须使用ufuncs乘法和乘方来确保对所有输入执行正确的操作。
矩阵类是ndarray的Python子类,可以用作如何构造自己的ndarray子类的参考。可以从其他矩阵,字符串以及可以转换为的任何其他东西创建矩阵ndarray
。名称“ mat”是NumPy中“矩阵”的别名。
|
注意 不再建议使用此类,即使对于线性 |
|
将输入解释为矩阵。 |
|
从字符串,嵌套序列或数组构建矩阵对象。 |
示例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()
用户必须手动调用该方法,以确保对数组的任何更改实际上都已写入磁盘。
创建到存储在磁盘上的二进制文件中的数组的内存映射。 |
|
|
将阵列中的所有更改写入磁盘上的文件。 |
例:
>>> 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开始,如果需要字符串数组,建议使用,或数组
,并使用模块中的free函数进行快速矢量化字符串操作。dtype
object_
string_
unicode_
numpy.char
这些是string_
类型或
unicode_
类型的增强型数组。这些阵列从继承
ndarray
,但专门定义的操作+
,*
以及%
在(广播)元件逐元素的基础。这些操作在ndarray
字符类型的标准上不可用。此外,chararray
具有所有标准string
(和unicode
)方法,并在逐个元素的基础上执行它们。也许是为了创建一个chararray最简单的方法就是使用self.view(chararray)
其中的自我是海峡或Unicode数据类型的ndarray。但是,也可以使用numpy.chararray
构造函数或通过
numpy.char.array
函数来创建chararray
:
|
提供有关字符串和Unicode值数组的便捷视图。 |
|
创建一个 |
与str数据类型的标准ndarray的另一个区别是chararray继承了Numarray引入的功能,即在项目检索和比较操作时,将忽略数组中任何元素末尾的空白。
numpy.rec
)¶也可以看看
NumPy提供了recarray
允许作为属性访问结构化数组的字段的类,以及一个对应的标量数据类型对象record
。
构造一个ndarray,允许使用属性进行字段访问。 |
|
允许字段访问作为属性查找的数据类型标量。 |
为了向后兼容并作为标准的“容器”类,已将Numeric的UserArray传递给NumPy,并将numpy.lib.user_array.container
其命名为
Container类是Python类,其self.array属性是ndarray。使用numpy.lib.user_array.container可能比使用ndarray本身更容易进行多重继承,因此默认情况下将其包括在内。这里没有提及它的存在,因此没有记录,因为如果可以的话,建议您直接使用ndarray类。
|
标准容器类,可轻松实现多重继承。 |
迭代器是数组处理的强大概念。本质上,迭代器实现了通用的for循环。如果myiter是迭代器对象,则Python代码:
for val in myiter:
...
some code involving val
...
反复调用,直到由迭代器引发。有几种遍历数组的方法可能有用:默认迭代,平面迭代和-
维枚举。val = next(myiter)
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属性返回一个迭代器,该迭代器将以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
在这里,我使用了内置的枚举迭代器来返回迭代器索引和值。