标准数组的子类

NumPy中的ndarray是一种“新式”Python内置类型。因此,如果需要,它可以继承自(以Python或C语言)。因此,它可以为许多有用的课程形成基础。通常,对数组对象进行子类化还是仅将核心数组组件作为新类的内部组成部分是一个困难的决定,并且可以是简单的选择。NumPy有几种简化新对象与其他数组对象交互的工具,所以最终的选择可能并不重要。简化问题的一种方法是询问自己,您感兴趣的对象是否可以作为单个数组来替换,或者是否真的需要两个或更多个数组作为其核心。

请注意,asarray总是返回基类ndarray。如果您确信您使用数组对象可以处理ndarray的任何子类,则可以使用asanyarray来允许子类在您的子例程中更干净地传播。In principal a subclass could redefine any aspect of the array and therefore, under strict guidelines, asanyarray would rarely be useful. 但是,数组对象的大多数子类不会重新定义数组对象的某些方面,如缓冲区接口或数组的属性。然而,一个重要的例子是,为什么你的子程序可能无法处理数组的任意子类,矩阵重新定义了“*”运算符是矩阵乘法,而不是逐个元素的乘法。

特殊属性和方法

也可以看看

Subclassing ndarray

NumPy提供了几个类可以自定义的钩子:

class.__numpy_ufunc__(ufunc, method, i, inputs, **kwargs)

版本1.11中的新功能

任何类(ndarray子类或不)都可以定义此方法来覆盖NumPy的ufuncs的行为。这与Python的__mul__和其他二进制操作例程非常类似。

  • ufunc is the ufunc object that was called.
  • method is a string indicating which Ufunc method was called (one of "__call__", "reduce", "reduceat", "accumulate", "outer", "inner").
  • i输入self的索引。
  • inputsufunc的输入参数的元组
  • kwargs是包含ufunc的可选输入参数的字典。如果给出,out参数总是包含在kwargs中。有关详细信息,请参阅Universal functions (ufunc)中的讨论。

该方法应返回操作的结果,或者如果未执行请求的操作,则返回NotImplemented

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

如果ndarray子类定义了__numpy_ufunc__方法,则会禁用__array_wrap____array_prepare____array_priority__

注意

除了ufuncs之外,即使它不是Ufunc,__numpy_ufunc__也会覆盖numpy.dot的行为。

注意

If you also define right-hand binary operator override methods (such as __rmul__) or comparison operations (such as __gt__) in your class, they take precedence over the __numpy_ufunc__ mechanism when resolving results of binary operations (such as ndarray_obj * your_obj).

The technical special case is: ndarray.__mul__ returns NotImplemented if the other object is not a subclass of ndarray, and defines both __numpy_ufunc__ and __rmul__. 类似的例外适用于除乘法之外的其他操作。

In such a case, when computing a binary operation such as ndarray_obj * your_obj, your __numpy_ufunc__ method will not be called. 相反,按照标准的Python操作符覆盖规则,执行转移到右侧的__rmul__操作。

Similar special case applies to in-place operations: If you define __rmul__, then ndarray_obj *= your_obj will not call your __numpy_ufunc__ implementation. 相反,默认的Python行为ndarray_obj = ndarray_obj * your_obj / t0>发生。

请注意,上述讨论仅适用于Python的内置二进制操作机制。np.multiply(ndarray_obj, your_obj) always calls only your __numpy_ufunc__, as expected.

class.__array_finalize__(obj)

当系统从obj内部分配一个新数组时,系统会调用此方法,其中objndarray的子类(子类型)。它可以用于在构建之后更改self的属性(例如确保2-d矩阵)或更新来自“父”的元信息。子类继承默认实现这种方法什么都不做。

class.__array_prepare__(array, context=None)

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

class.__array_wrap__(array, context=None)

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

class.__array_priority__

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

class.__array__([dtype])

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

矩阵对象

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

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

  2. 矩阵对象始终是二维的。这具有深远的影响,因为m.ravel()仍然是二维的(在第一维中具有1),并且项选择返回二维对象,因此序列行为与数组基本上不同。

  3. 矩阵对象乘法乘法是矩阵乘法。确保你理解这个函数,你可能想要接收矩阵。特别是鉴于当m是矩阵时,asanyarray(m)返回矩阵的事实。

  4. 矩阵对象将权力矩阵提升为权力。关于在使用asanyarray(...)获取数组对象的函数内部使用电源的警告同样适用于此事实。

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

  6. 矩阵具有使计算更容易的特殊属性。这些是

    matrix.T 返回矩阵的转置。
    matrix.H 返回self的(复数)共轭转置。
    matrix.I 返回可逆self的(乘法)倒数。
    matrix.A Return self as an ndarray object.

警告

矩阵对象乘法乘法,'*'和功率'**'分别是矩阵乘法和矩阵乘法。如果你的子程序可以接受子类并且你不转换为基类数组,那么你必须使用ufuncs multiply和power来确保你对所有输入执行了正确的操作。

矩阵类是ndarray的Python子类,可用作构建ndarray自己的子类的参考。矩阵可以从其他矩阵,字符串和其他可以转换为ndarray的其他任何东西创建。名称“mat”是NumPy中“matrix”的别名。

matrix 从类似数组的对象或数据字符串中返回矩阵。
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

注意

为了向后兼容Numarray存在chararray类,不推荐用于新开发。Starting from numpy 1.4, if one needs arrays of strings, it is recommended to use arrays of dtype object_, string_ or unicode_, and use the free functions in the numpy.char module for fast vectorized string operations.

这些是string_类型或unicode_类型的增强型数组。这些数组继承自ndarray,但是专门定义了+*%广播)逐个元素的基础。这些操作在字符类型的标准ndarray上不可用。另外,chararray具有所有标准的string(和unicode)方法,以逐个元素为基础执行它们。Perhaps the easiest way to create a chararray is to use self.view(chararray) where self is an ndarray of str or unicode data-type. 但是,也可以使用numpy.chararray构造函数或通过numpy.char.array函数创建chararray:

chararray 为字符串和unicode值数组提供一个方便的视图。
core.defchararray.array(obj [,itemsize,...]) 创建一个chararray

与str数据类型的标准ndarray的另一个区别是chararray继承了Numarray引入的特性,即数组中任何元素末尾的空白在项目检索和比较操作时将被忽略。

记录数组(numpy.rec

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

recarray 构建一个允许使用属性进行字段访问的ndarray。
record 数据类型标量,允许字段访问作为属性查找。

被屏蔽的数组(numpy.ma

也可以看看

Masked arrays

标准容器类

为了向后兼容,并且作为标准的“容器”类,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 [,...]) 容易多重继承的标准容器类。

数组迭代器

迭代器是数组处理的强大概念。从本质上讲,迭代器实现了一个广义的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-loops。

>>> 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 数组上的一维迭代器。

如前所述,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 多维索引迭代器。

有时在迭代时获取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)