标准数组子类

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的ufuncs的行为。 这与Python的 __mul__ 和其他二进制操作例程非常相似。

  • ufunc 是被调用的ufunc对象
  • method 是一个字符串,表示调用了哪个Ufunc方法 (one of "__call__", "reduce", "reduceat", "accumulate", "outer", "inner").
  • inputsufunc 的输入参数的元组。
  • kwargs 是一个包含ufunc的可选输入参数的字典。如果给出,任何 out 参数, 位置和关键字 都是在 kwargs 中作为元组传递的. 更多细节参见 通用函数 (ufunc)

该方法应该返回操作的结果,如果请求的操作没有实现,则返回 NotImplemented

如果输入或输出参数之一具有 __array_ufunc__ 方法,则执行它而不是ufunc。 如果多个参数实现 __array_ufunc__ ,则按顺序尝试它们:超类之前的子类, 输出之前的输入,否则从左到右。 返回 NotImplemented 之外的第一个例程确定结果。 如果所有 __array_ufunc__ 操作都返回 NotImplemented ,则会引发 TypeError

注解

我们打算将numpy函数重新实现为广义的Ufunc,在这种情况下, 它们可以被 __array_ufunc__ 方法覆盖。 一个主要的候选者是 matmul , 它当前不是Ufunc,但可以相对容易地被重写为(一组)广义Ufuncs。 使用诸如 medianminargsort 等函数也可能发生同样的情况。

与python中的一些其他特殊方法一样,例如 __hash____iter__ , 可以通过设置 __array_ufunc_ = None 来指示你的类不支持ufunc。 当对设置 __array_ufunc__= None 的对象上调用Ufuncs时总是引发 TypeError

__array_ufunc__ 的存在也会影响ndarray如何处理二进制操作, 如 arr + objarr < obj ,当 arr 是一个 ndarrayobj 是一个自定义类的实例。 有两种可能性。 如果 obj.__array_ufunc__ 存在而不是 None , 则 ndarray.__add__ 和friends将委托给ufunc机制,这意味着 arr + obj 变 为 add ,然后添加调用 obj.__array_ufunc__ 。 如果要定义一个类似于数组的对象,这将非常有用

或者,如果 obj.__array_ufunc__ 设置为 None ,那么作为一种特殊情况, 像 ndarray.__add__ 这样的特殊方法会注意到这一点并无条件地引发 TypeError 。 如果要创建通过二进制操作与数组交互的对象,但这些对象本身不是数组,则此选项非常有用。 例如,单位处理系统可能有一个对象 m 代表 单位,并希望支持语法 arr * m 来表示该数组具有 单位, 但不希望以其他方式通过ufuncs或其他方式与数组进行交互。 这可以通过设置 __array_ufunc__ = None 并 定义mul和rmul方法来完成。(注意,这意味着编写始终返回 NotImplemented__array_ufunc__ 与设置 __array_ufunc__ = None 不完全相同:在前一种情况下,arr + obj 将引发 TypeError , 而在后一种情况下,可以定义 __radd__ 方法防止这种情况。)

以上内容不适用于就地运算符,ndarray 永远不会返回 NotImplemented 。 因此,arr += obj 总是会导致 TypeError 。 这是因为对于阵列就地操作一般不能用简单的反向操作代替。 (例如,默认情况下,arr += obj 将转换为 arr = arr + obj ,即``arr``将被替换,与内部数组操作的预期相反。)

注解

如果定义了 __array_ufunc__:

  • 如果不是 ndarray 的子类,我们建议你的类定义像ndarray那样委托给ufuncs的特殊方法, 比如 __add____lt__ 。一个简单的方法是从 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__ 方法,则会禁用下面针对ufuncs描述的 __array_wrap____array_prepare__,:data:`__array_priority__`机制

class.__array_finalize__(obj)

只要系统在内部从obj分配一个新数组,就会调用此方法,其中obj是 ndarray 的子类(子类型)。 它可以用于在构造之后更改self的属性(例如,以确保2-d矩阵),或者从父类更新元信息。 子类继承此方法的默认实现,该方法不执行任何操作。

class.__array_prepare__(array, context=None)

在每个 ufunc 的开头,在具有最高数组优先级的输入对象上调用此方法, 或者在指定了一个输出对象的情况下调用此方法。传入输出数组,返回的任何内容都传递给ufunc。 子类继承此方法的默认实现,它只返回未修改的输出数组。子类可以选择使用此方法将输出数组转换为子类的实例, 并在将数组返回到ufunc进行计算之前更新元数据。

注解

对于ufuncs,希望最终弃用这个方法,而不是 __array_ufunc__

class.__array_wrap__(array, context=None)

在每个 ufunc 的末尾,在具有最高数组优先级的输入对象上调用此方法, 如果指定了一个输出对象,则调用此方法。 传入ufunc-computed数组, 并将返回的任何内容传递给用户。 子类继承此方法的默认实现,该实现将数组转换为对象类的新实例。 子类可以选择使用此方法将输出数组转换为子类的实例,并在将数组返回给用户之前更新元数据。

注解

For ufuncs, it is hoped to eventually deprecate this method in favour of __array_ufunc__.

class.__array_priority__

此属性的值用于确定在返回对象的Python类型有多种可能性的情况下要返回的对象类型。 子类为此属性继承默认值0.0。

注解

For ufuncs, it is hoped to eventually deprecate this method in favour of __array_ufunc__.

class.__array__([dtype])

如果使用具有 __array__ 方法的类(ndarray子类)作为 ufunc 的输出对象,则结果将被写入由 __array__ 返回的对象。 在输入数组上进行类似的转换。

矩阵对象

注解

强烈建议不要使用 matrix 子类。如下所述,它使得处理矩阵和常规数组的编写函数变得非常困难。 目前,它们主要用于与 scipy.sparse 的交互。然而,我们希望为这种使用提供一个替代方案, 并最终删除 matrix 子类。

matrix 对象继承自ndarray,因此,它们具有相同的ndarrays属性和方法。 但是,矩阵对象有六个重要区别,当您使用矩阵但希望它们像数组一样时,可能会导致意外结果:

  1. 矩阵对象可以使用字符串表示法创建,从而允许Matlab风格的语法, 其中空格、分隔列和分号 (';') 分隔行

  2. 矩阵对象总是二维的.这具有深远的意义,因为 m.ravel() 仍然是二维的(在第一个维度中有一个1), 项选择返回二维对象,因此序列行为与数组有根本的不同。

  3. 矩阵对象覆写的乘法是矩阵乘法。确保您对可能希望接收矩阵的函数有所了解。 特别是考虑到当m是矩阵时 asanyarray(m) 返回矩阵的事实

  4. 矩阵对象覆写幂是将矩阵提升为幂的矩阵。关于在使用asanyarray(…)获取数组对象的函数内部使用幂的相同警告适用于此事实。

  5. 矩阵对象的默认 __array_priority__ 是10.0,因此与ndarrays的混合操作总是产生矩阵。

  6. 矩阵具有特殊属性,使计算更容易,下面是这些特殊属性:

    matrix.T Returns the transpose of the matrix.
    matrix.H Returns the (complex) conjugate transpose of self.
    matrix.I Returns the (multiplicative) inverse of invertible self.
    matrix.A Return self as an ndarray object.

警告

矩阵对象覆盖乘法,* 和幂,** 分别是矩阵乘法和矩阵幂。 如果您的子例程可以接受子类并且您没有转换为基类数组, 则必须使用``ufuncs`` multiplypower 来确保您对所有输入执行正确的操作

矩阵类是 ndarray 的Python子类,可以用作如何构造自己的 ndarray 子类的参考。 可以从其他矩阵,字符串以及可以转换为 ndarray 的任何其他内容创建矩阵。 名称 mat 是NumPy中 matrix 的别名

matrix

注解

It is no longer recommended to use this class, even for linear

asmatrix(data[, dtype]) Interpret the input as a matrix.
bmat(obj[, ldict, gdict]) Build a matrix object from a string, nested sequence, or array.

Example 1: 从字符串创建矩阵

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

Example 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]])

Example 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 Create a memory-map to an array stored in a binary file on disk.
memmap.flush() Write any changes in the array to the file on disk.

Example:

>>> 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 模块中的free函数进行快速矢量化字符串操作

这些是 string_unicode_ 类型的增强数组。这些数组继承自 ndarray , 但是在(逐个)元素的基础上特别定义了操作``+``, *, % 。这些操作在字符类型的标准 ndarray 上不可用。 此外, chararray 具有所有标准 stringunicode 方法, 在逐个元素的基础上执行它们。也许创建chararray的最简单方法是使用 self.view(chararray) , 其中self是str或unicode数据类型的ndarray。但是,也可以使用 numpy.chararray 构造函数或 通过 numpy.char.array 函数创建chararray:

chararray Provides a convenient view on arrays of string and unicode values.
core.defchararray.array(obj[, itemsize, …]) Create a chararray.

与str数据类型的标准ndarray的另一个不同之处在于chararray继承了Numarray引入的特性, 即在项检索和比较操作中将忽略数组中任何元素末尾的空白空间

记录数组 (numpy.rec)

NumPy提供了 recarray 类,它允许访问结构化数组的字段作为属性,以及相应的标量数据类型对象 record

recarray Construct an ndarray that allows field access using attributes.
record A data-type scalar that allows field access as attribute lookup.

掩码数组 (numpy.ma)

参见

Masked arrays

标准容器类s

为了向后兼容并作为标准的“容器”类,Numeric的UserArray已经被带到NumPy并命名为 numpy.lib.user_array.container 容器类是一个Python类,其 self.array 属性是 一个ndarray。 使用 numpy.lib.user_array.container 比使用ndarray本身更容易 进行多重继承,因此默认包含它。 除了提及它的存在之外,这里没有记录,因为如果可 以的话,我们鼓励你直接使用ndarray类。

numpy.lib.user_array.container(data[, …]) Standard container-class for easy multiple-inheritance.

数组迭代器

迭代器是数组处理的强大概念。 本质上,迭代器实现了一个通用的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 A 1-D iterator over the array.

如前所述,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

在这里,我使用了内置的枚举迭代器来返回迭代器索引以及值。

N维枚举

ndenumerate(arr) Multidimensional index iterator.

有时在迭代时获得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 Produce an object that mimics broadcasting.

广播的一般概念也可以使用 broadcast 迭代器从Python获得。 此对象将N个对象作为输入,并返回一个迭代器,该迭代器返回元组,提供广播结果中的每个输入序列元素。

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