NumPy-1-26-中文文件-五-

绝不原创的飞龙發表於2024-06-24

NumPy 1.26 中文文件(五)

原文:numpy.org/doc/

numpy.ndenumerate

原文:numpy.org/doc/1.26/reference/generated/numpy.ndenumerate.html

class numpy.ndenumerate(arr)

多維索引迭代器。

返回一個迭代器,產生陣列座標和值的對。

引數:

arrndarray

輸入陣列。

另請參見:

ndindexflatiter

示例

>>> a = np.array([[1, 2], [3, 4]])
>>> for index, x in np.ndenumerate(a):
...     print(index, x)
(0, 0) 1
(0, 1) 2
(1, 0) 3
(1, 1) 4 

numpy.ndindex

原文:numpy.org/doc/1.26/reference/generated/numpy.ndindex.html

class numpy.ndindex(*shape)

用於索引陣列的 N 維迭代器物件。

給定陣列的形狀,一個ndindex例項會遍歷陣列的 N 維索引。在每次迭代時,一個索引元組被返回,最後一個維度先被迭代。

引數:

shapeints 或一個整數元組

陣列的每個維度大小可以作為單獨的引數傳遞,也可以作為元組的元素傳遞。

參見

ndenumerate, flatiter

示例

Dimensions as individual arguments

>>> for index in np.ndindex(3, 2, 1):
...     print(index)
(0, 0, 0)
(0, 1, 0)
(1, 0, 0)
(1, 1, 0)
(2, 0, 0)
(2, 1, 0) 

相同的維度 - 但以元組形式(3, 2, 1)

>>> for index in np.ndindex((3, 2, 1)):
...     print(index)
(0, 0, 0)
(0, 1, 0)
(1, 0, 0)
(1, 1, 0)
(2, 0, 0)
(2, 1, 0) 

方法

ndincr() 將多維索引增加一。

numpy.nested_iters

原文:numpy.org/doc/1.26/reference/generated/numpy.nested_iters.html

numpy.nested_iters(op, axes, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', buffersize=0)

建立用於巢狀迴圈中的 nditer

建立一個 nditer 物件的元組,它在 op 引數的不同軸上以巢狀迴圈的方式進行迭代。第一個迭代器用於最外層迴圈,最後一個用於最內層迴圈。推進一個將會使後續的迭代器指向它的新元素。

引數:

op ndarray 或陣列樣式的序列

要迭代的陣列。

axes int 的列表的列表

每個專案都被用作一個“op_axes”引數傳遞給 nditer

flags, op_flags, op_dtypes, order, casting, buffersize(可選)

參見相同名稱的 nditer 引數

返回:

iters nditer 的元組

對於 axes 中的每個專案,從最外層開始的一個 nditer

另請參閱

nditer

示例

基本用法。注意,由於我們將第一個迭代器的軸指定為 [1],因此 y 是 [a[:, 0, :], a[:, 1, 0], a[:, 2, :]] 的“扁平化”版本

>>> a = np.arange(12).reshape(2, 3, 2)
>>> i, j = np.nested_iters(a, [[1], [0, 2]], flags=["multi_index"])
>>> for x in i:
...      print(i.multi_index)
...      for y in j:
...          print('', j.multi_index, y)
(0,)
 (0, 0) 0
 (0, 1) 1
 (1, 0) 6
 (1, 1) 7
(1,)
 (0, 0) 2
 (0, 1) 3
 (1, 0) 8
 (1, 1) 9
(2,)
 (0, 0) 4
 (0, 1) 5
 (1, 0) 10
 (1, 1) 11 

numpy.flatiter

原文:numpy.org/doc/1.26/reference/generated/numpy.flatiter.html

class numpy.flatiter

用於遍歷陣列的平坦迭代器物件。

任意陣列xflatiter迭代器是由x.flat返回的。它允許像遍歷 1-D 陣列一樣遍歷陣列,可以透過 for 迴圈或呼叫其next方法來實現。

迭代按行優先、C 風格順序進行(最後的索引變化最快)。迭代器還可以使用基本切片或高階索引進行索引。

另請參閱

ndarray.flat

返回陣列的平坦迭代器。

ndarray.flatten

返回陣列的平坦副本。

注意事項

不能透過呼叫flatiter建構函式直接從 Python 程式碼中構建flatiter迭代器。

示例

>>> x = np.arange(6).reshape(2, 3)
>>> fl = x.flat
>>> type(fl)
<class 'numpy.flatiter'>
>>> for item in fl:
...     print(item)
...
0
1
2
3
4
5 
>>> fl[2:4]
array([2, 3]) 

屬性:

base

被遍歷的陣列的引用。

coords

當前座標的 N 維元組。

index

陣列中的當前平坦索引。

方法

copy() 獲取迭代器的 1-D 陣列副本。

numpy.lib.Arrayterator

原文:numpy.org/doc/1.26/reference/generated/numpy.lib.Arrayterator.html

class numpy.lib.Arrayterator(var, buf_size=None)

大陣列的緩衝迭代器。

Arrayterator建立一個緩衝迭代器,用於以小的連續塊讀取大陣列。該類對儲存在檔案系統中的物件非常有用。它允許對物件進行迭代而不是讀取所有記憶體;相反,將讀取和迭代小塊。

Arrayterator可以與支援多維切片的任何物件一起使用。這包括 NumPy 陣列,也包括來自 Scientific.IO.NetCDF 或 pynetcdf 的變數等。

引數:

vararray_like

要迭代的物件。

buf_sizeint, 可選

緩衝區大小。如果提供了buf_size,則將讀取到記憶體的資料的最大數量是buf_size元素。預設為 None,將盡可能多地讀取元素到記憶體中。

參見

ndenumerate

多維陣列迭代器。

flatiter

平面陣列迭代器。

memmap

建立一個對映到儲存在磁碟上的二進位制檔案中的陣列的記憶體對映。

注意

該演算法首先找到一個“執行維度”,沿著這個維度將提取塊。給定一個維度陣列(d1, d2, ..., dn),例如如果buf_size小於d1,則將使用第一維。另一方面,如果d1 < buf_size < d1*d2,則將使用第二維,依此類推。沿著這個維度提取塊,並且當返回最後一個塊時,該過程將從下一個維度繼續進行,直到所有元素都被讀取。

例子

>>> a = np.arange(3 * 4 * 5 * 6).reshape(3, 4, 5, 6)
>>> a_itor = np.lib.Arrayterator(a, 2)
>>> a_itor.shape
(3, 4, 5, 6) 

現在我們可以對a_itor進行迭代,它會返回大小為二的陣列。由於buf_size比任何維度都小,首先將迭代第一維:

>>> for subarr in a_itor:
...     if not subarr.all():
...         print(subarr, subarr.shape) 
>>> # [[[[0 1]]]] (1, 1, 1, 2) 

屬性:

var

buf_size

start

stop

step

shape

要迭代的陣列的形狀。

flat

用於 Arrayterator 物件的一維平面迭代器。

numpy.iterable

numpy.org/doc/1.26/reference/generated/numpy.iterable.html

numpy.iterable(y)

檢查物件是否可以迭代。

引數:

y object

輸入物件。

返回值:

b bool

如果物件具有迭代器方法或是一個序列,則返回True,否則返回False

注意事項

在大多數情況下,np.iterable(obj)的結果與isinstance(obj, collections.abc.Iterable)一致。一個顯著的例外是對於 0 維陣列的處理:

>>> from collections.abc import Iterable
>>> a = np.array(1.0)  # 0-dimensional numpy array
>>> isinstance(a, Iterable)
True
>>> np.iterable(a)
False 

示例

>>> np.iterable([1, 2, 3])
True
>>> np.iterable(2)
False 

遍歷陣列

原文:numpy.org/doc/1.26/reference/arrays.nditer.html

注意

陣列支援迭代器協議,可以像 Python 列表一樣進行迭代。檢視快速入門指南中的“索引、切片和迭代”部分,瞭解基本用法和示例。本文件的其餘部分介紹了nditer物件,並涵蓋了更高階的用法。

nditer迭代器物件在 NumPy 1.6 中引入,提供了許多靈活的方式以系統化的方式訪問一個或多個陣列的所有元素。本頁面介紹瞭如何在 Python 中對陣列進行計算的一些基本方法,然後總結了如何可以在 Cython 中加速內部迴圈。由於 Python 對nditer的暴露相對直接地對映了 C 陣列迭代器 API,這些想法也將對使用 C 或 C++進行陣列迭代工作提供幫助。

單陣列迭代

nditer最基本的任務是訪問陣列的每個元素。使用標準的 Python 迭代器介面逐個提供每個元素。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a):
...     print(x, end=' ')
...
0 1 2 3 4 5 

對於這種迭代需要注意的重要事項是,順序是選擇與陣列的記憶體佈局匹配而不是使用標準的 C 或 Fortran 順序。這樣做是為了訪問效率,體現了預設情況下只需訪問每個元素而不考慮特定順序的思想。透過迭代前一陣列的轉置,與以 C 順序複製該轉置進行比較,我們可以看到這一點。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a.T):
...     print(x, end=' ')
...
0 1 2 3 4 5 
>>> for x in np.nditer(a.T.copy(order='C')):
...     print(x, end=' ')
...
0 3 1 4 2 5 

aa.T的元素以相同順序遍歷,即它們在記憶體中儲存的順序,而a.T.copy(order=’C’)的元素以不同順序訪問,因為它們已經放置到不同的記憶體佈局中。

控制迭代順序

有時重要的是按照特定順序訪問陣列的元素,而不考慮記憶體中元素的佈局。nditer物件提供了一個order引數來控制迭代的這個方面。預設情況下,具有上述行為的行為是 order=’K’以保持現有順序。這可以透過 order=’C’覆蓋為 C 順序和 order=’F’為 Fortran 順序。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, order='F'):
...     print(x, end=' ')
...
0 3 1 4 2 5
>>> for x in np.nditer(a.T, order='C'):
...     print(x, end=' ')
...
0 3 1 4 2 5 

修改陣列值

預設情況下,nditer將輸入運算元視為只讀物件。要能夠修改陣列元素,必須使用‘readwrite’‘writeonly’每個運算元標記來指定讀寫或僅寫模式。

nditer 然後將生成可修改的緩衝區陣列。然而,因為 nditer 必須在迭代結束時將此緩衝區資料複製回原始陣列,所以必須透過兩種方法之一來標誌迭代何時結束。您可以選擇:

  • with語句使用 nditer 作為上下文管理器,並在上下文退出時將臨時資料寫回。
  • 在迭代結束時呼叫迭代器的close方法,這將觸發寫回操作。

迭代器不能在close被呼叫或者它的上下文退出後繼續迭代。

示例

>>> a = np.arange(6).reshape(2,3)
>>> a
array([[0, 1, 2],
 [3, 4, 5]])
>>> with np.nditer(a, op_flags=['readwrite']) as it:
...    for x in it:
...        x[...] = 2 * x
...
>>> a
array([[ 0,  2,  4],
 [ 6,  8, 10]]) 

如果你正在編寫需要支援較舊版本的 numpy 的程式碼,請注意,在 1.15 之前,nditer不是一個上下文管理器,並且沒有close方法。相反,它依靠解構函式來初始化緩衝區的寫回。

使用外部迴圈

到目前為止,所有的示例中,a的元素都是由迭代器逐個提供的,因為所有的迴圈邏輯都是迭代器內部的。雖然這很簡單和方便,但效率不高。更好的方法是將一維內層迴圈移到你的程式碼中,迭代器之外。這樣,NumPy 的向量化操作可以在更大的元素塊上使用。

nditer將嘗試提供儘可能大的塊給內部迴圈。透過強制使用'C'和'F'順序,我們可以得到不同的外部迴圈大小。透過指定迭代器標誌來啟用此模式。

注意,預設情況下保持本機記憶體順序,迭代器能夠提供一個單一的一維塊,而當強制使用 Fortran 順序時,它必須提供三個塊,每個塊有兩個元素。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop']):
...     print(x, end=' ')
...
[0 1 2 3 4 5] 
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 

跟蹤一個索引或多索引

在迭代過程中,您可能希望在計算中使用當前元素的索引。例如,您可能希望以記憶體順序訪問陣列的元素,但使用 C 順序、Fortran 順序或多維索引在不同的陣列中查詢值。

索引由迭代器物件本身跟蹤,並透過indexmulti_index屬性訪問,具體取決於請求了哪個。下面的示例展示了列印輸出,展示了索引的進展:

示例

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> for x in it:
...     print("%d <%d>" % (x, it.index), end=' ')
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> for x in it:
...     print("%d <%s>" % (x, it.multi_index), end=' ')
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     for x in it:
...         x[...] = it.multi_index[1] - it.multi_index[0]
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

跟蹤一個索引或多索引與使用外部迴圈不相容,因為它需要每個元素一個不同的索引值。如果嘗試組合這些標誌,nditer物件將引發異常。

示例

>>> a = np.zeros((2,3))
>>> it = np.nditer(a, flags=['c_index', 'external_loop'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Iterator flag EXTERNAL_LOOP cannot be used if an index or multi-index is being tracked 

替代迴圈和元素訪問

為了在迭代時更方便地訪問其屬性,nditer具有與迭代器物件本身明確工作的用於迭代的替代語法。透過這種迴圈結構,可以透過對迭代器進行索引來訪問當前值。其它屬性,例如跟蹤的索引,保持與之前相同。下面的示例產生了與前一節中相同的結果。

示例

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> while not it.finished:
...     print("%d <%d>" % (it[0], it.index), end=' ')
...     is_not_finished = it.iternext()
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> while not it.finished:
...     print("%d <%s>" % (it[0], it.multi_index), end=' ')
...     is_not_finished = it.iternext()
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     while not it.finished:
...         it[0] = it.multi_index[1] - it.multi_index[0]
...         is_not_finished = it.iternext()
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

對陣列元素進行緩衝

在強制迭代順序時,我們觀察到外部迴圈選項可能以較小的塊提供元素,因為元素不能以恆定步長按適當順序訪問。在編寫 C 程式碼時,這通常沒問題,但在純 Python 程式碼中,這可能會導致效能顯著降低。

透過啟用緩衝模式,迭代器提供給內部迴圈的塊可以變得更大,從而顯著減少了 Python 直譯器的開銷。在強制 Fortran 迭代順序的示例中,啟用緩衝時,內部迴圈可以一次看到所有元素。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 
>>> for x in np.nditer(a, flags=['external_loop','buffered'], order='F'):
...     print(x, end=' ')
...
[0 3 1 4 2 5] 

迭代特定資料型別

有時有必要將陣列視為與其儲存方式不同的資料型別。例如,即使被操作的陣列是 32 位浮點數,也可能希望在 64 位浮點數上進行所有計算。除了編寫低階 C 程式碼時,通常最好讓迭代器處理複製或緩衝,而不是在內部迴圈中自己進行資料型別轉換。

有兩種機制可以實現這一點,臨時複製和緩衝模式。透過臨時複製,使用新資料型別製作整個陣列的副本,然後對副本進行迭代。在所有迭代完成之後,可以透過更新原始陣列的方式進行寫訪問。臨時複製的主要缺點是,如果迭代資料型別的 itemsize 比原始資料型別更大,臨時副本可能會佔用大量記憶體。

緩衝模式減輕了記憶體使用問題,並且比製作臨時副本更加快取友好。除了特殊情況,在迭代器外需要一次性整個陣列的情況下,推薦使用緩衝而不是臨時複製。在 NumPy 中,ufuncs 和其他函式使用緩衝來支援以最小記憶體開銷支援靈活輸入。

在我們的示例中,我們將以複雜資料型別處理輸入陣列,以便我們可以對負數取平方根。在不啟用複製或緩衝模式的情況下,如果資料型別與迭代器不精確匹配,迭代器將引發異常。

示例

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand required copying or buffering, but neither copying nor buffering was enabled 

在複製模式中,“copy”被指定為每個運算元的標誌。這是為了以每個運算元的方式提供控制。緩衝模式被指定為迭代器標誌。

示例

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_flags=['readonly','copy'],
...                 op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 

迭代器使用 NumPy 的轉換規則來確定是否允許特定的轉換。預設情況下,它強制執行‘safe’轉換。這意味著,例如,如果您嘗試將 64 位浮點數陣列視為 32 位浮點數陣列,它會引發異常。在許多情況下,‘same_kind’規則是最合理的規則,因為它允許從 64 位轉換為 32 位浮點數,但不允許從浮點數轉換為整數或從複數轉換為浮點數。

例項

>>> a = np.arange(6.)
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32']):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('float32') according to the rule 'safe' 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32'],
...                 casting='same_kind'):
...     print(x, end=' ')
...
0.0 1.0 2.0 3.0 4.0 5.0 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['int32'], casting='same_kind'):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('int32') according to the rule 'same_kind' 

當使用讀寫或僅寫運算元時,要注意的一點是在轉換回原始資料型別時可能會遇到問題。一個常見情況是用 64 位浮點數實現內部迴圈,使用‘same_kind’轉換來允許處理其他浮點型別。在只讀模式下,可以提供一個整數陣列,但在讀寫模式下會丟擲異常,因為轉換回陣列會違反轉換規則。

例項

>>> a = np.arange(6)
>>> for x in np.nditer(a, flags=['buffered'], op_flags=['readwrite'],
...                 op_dtypes=['float64'], casting='same_kind'):
...     x[...] = x / 2.0
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: Iterator requested dtype could not be cast from dtype('float64') to dtype('int64'), the operand 0 dtype, according to the rule 'same_kind' 

廣播陣列迭代

NumPy 有一組規則用於處理形狀不同的陣列,慣例上在函式接受多個運算元時會對這些規則進行應用,這些運算元合併在一起進行元素級操作。這稱為廣播。nditer物件可以在需要編寫這樣一個函式時為您應用這些規則。

舉個例子,我們列印出一個一維陣列和一個二維陣列進行廣播的結果。

例項

>>> a = np.arange(3)
>>> b = np.arange(6).reshape(2,3)
>>> for x, y in np.nditer([a,b]):
...     print("%d:%d" % (x,y), end=' ')
...
0:0 1:1 2:2 0:3 1:4 2:5 

當廣播錯誤發生時,迭代器會引發一個異常,其中包括輸入形狀,以幫助診斷問題。

例項

>>> a = np.arange(2)
>>> b = np.arange(6).reshape(2,3)
>>> for x, y in np.nditer([a,b]):
...     print("%d:%d" % (x,y), end=' ')
...
Traceback (most recent call last):
...
ValueError: operands could not be broadcast together with shapes (2,) (2,3) 

迭代器分配輸出陣列

NumPy 函式中的一個常見情況是根據輸入的廣播分配輸出,並且還有一個名為‘out’的可選引數,用於提供結果位置。nditer物件提供了一個方便的習語,使得支援這種機制變得非常容易。

我們將透過建立一個square函式來展示它是如何工作的,該函式將輸入的平方。讓我們從一個最小的函式定義開始,不包括‘out’引數支援。

例項

>>> def square(a):
...     with np.nditer([a, None]) as it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
...
>>> square([1,2,3])
array([1, 4, 9]) 

預設情況下,nditer對傳入的為 None 的運算元使用標誌‘allocate’和‘writeonly’。這意味著我們只需提供迭代器的兩個運算元,它就會處理其餘部分。

在新增‘out’引數時,我們必須顯式提供這些標誌,因為如果有人將陣列作為‘out’傳入,迭代器將預設為‘readonly’,而我們的內部迴圈會失敗。‘readonly’是輸入陣列的預設選項是為了防止意外觸發減少操作的混淆。如果預設選項是‘readwrite’,任何廣播操作都會觸發減少操作,這個主題稍後在本文件中會討論。

順便提一句,我們還要介紹‘no_broadcast’標誌,它將阻止輸出被廣播。這很重要,因為我們只希望每個輸出具有一個輸入值。聚合多個輸入值是一個需要特殊處理的約簡操作。雖然會因為迭代器標誌未明確啟用約簡而引發錯誤,但其結果僅限於禁用廣播的錯誤訊息對終端使用者更加易懂。要檢視如何將平方函式推廣為約簡函式,請檢視有關 Cython 部分中的平方和函式。

為了完整起見,我們還將新增‘external_loop’和‘buffered’標誌,因為出於效能原因,這些通常是您想要的。

示例

>>> def square(a, out=None):
...     it = np.nditer([a, out],
...             flags = ['external_loop', 'buffered'],
...             op_flags = [['readonly'],
...                         ['writeonly', 'allocate', 'no_broadcast']])
...     with it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
... 
>>> square([1,2,3])
array([1, 4, 9]) 
>>> b = np.zeros((3,))
>>> square([1,2,3], out=b)
array([1.,  4.,  9.])
>>> b
array([1.,  4.,  9.]) 
>>> square(np.arange(6).reshape(2,3), out=b)
Traceback (most recent call last):
  ...
ValueError: non-broadcastable output operand with shape (3,) doesn't
match the broadcast shape (2,3) 

外積迭代

任何二進位制操作都可以像outer中一樣以外積方式擴充套件為陣列操作,nditer物件透過顯式對映運算元的軸提供了一種實現這一點的方法。也可以使用newaxis索引來完成這個操作,但我們將向您展示如何直接使用 nditer 的op_axes引數來在沒有中間檢視的情況下完成此操作。

我們將進行一個簡單的外積計算,將第一個運算元的維度放在第二個運算元的維度之前。op_axes引數需要為每個運算元提供一個包含軸的列表,並提供了一個從迭代器的軸到運算元的軸的對映。

假設第一個運算元是一維的,第二個運算元是二維的。迭代器將具有三個維度,因此op_axes將有兩個包含三個元素的列表。第一個列表選擇第一個運算元的一個軸,其餘迭代器軸為-1,最終結果為[0, -1, -1]。第二個列表選擇第二個運算元的兩個軸,但不應與第一個運算元中選擇的軸重疊。它的列表是[-1, 0, 1]。輸出運算元按照標準方式對映到迭代器軸上,因此我們可以提供 None 而不是構造另一個列表。

在內部迴圈中的操作是直接乘法。所有外積相關的事情都由迭代器設定處理。

示例

>>> a = np.arange(3)
>>> b = np.arange(8).reshape(2,4)
>>> it = np.nditer([a, b, None], flags=['external_loop'],
...             op_axes=[[0, -1, -1], [-1, 0, 1], None])
>>> with it:
...     for x, y, z in it:
...         z[...] = x*y
...     result = it.operands[2]  # same as z
...
>>> result
array([[[ 0,  0,  0,  0],
 [ 0,  0,  0,  0]],
 [[ 0,  1,  2,  3],
 [ 4,  5,  6,  7]],
 [[ 0,  2,  4,  6],
 [ 8, 10, 12, 14]]]) 

請注意,一旦迭代器關閉,我們就無法訪問operands,而必須使用在上下文管理器中建立的引用。

約簡迭代

每當可寫運算元的元素少於完整迭代空間時,該運算元正在進行約簡。nditer物件要求任何約簡運算元都被標記為讀寫,並且僅在提供‘reduce_ok’作為迭代器標誌時允許約簡。

以簡單的例子為例,考慮計算陣列中所有元素的和。

例子

>>> a = np.arange(24).reshape(2,3,4)
>>> b = np.array(0)
>>> with np.nditer([a, b], flags=['reduce_ok'],
...                     op_flags=[['readonly'], ['readwrite']]) as it:
...     for x,y in it:
...         y[...] += x
...
>>> b
array(276)
>>> np.sum(a)
276 

當組合約簡和分配運算元時,情況變得有點棘手。在開始迭代之前,任何約簡運算元必須初始化為其起始值。以下是我們如何做到這一點,對a的最後一個軸進行求和。

例子

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]])
>>> np.sum(a, axis=2)
array([[ 6, 22, 38],
 [54, 70, 86]]) 

進行緩衝進行約簡需要在設定期間進行另一個調整。通常,迭代器構造涉及將可讀陣列的第一個緩衝區複製到緩衝區中。任何約簡運算元都是可讀的,所以它可能被讀入緩衝區。不幸的是,在這個緩衝操作完成後初始化運算元的值將不會反映在迭代開始時的緩衝區中,將產生垃圾結果。

迭代器標誌“delay_bufalloc”用於允許迭代器分配的約簡運算元與緩衝共存。設定此標誌時,迭代器將保留其緩衝區,直到接收到重置訊號,之後將準備好進行常規迭代。如果我們同時啟用緩衝,那麼前面的例子看起來是這樣的。

例子

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok',
...                                  'buffered', 'delay_bufalloc'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     it.reset()
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]]) 

將內部迴圈放入 Cython 中

那些希望從他們的低階操作中獲得真正好的效能的人應該強烈考慮直接使用 C 提供的迭代 API,但對於那些不熟悉 C 或 C++的人來說,Cython 是一個效能合理的中間選擇。對於nditer物件,這意味著讓迭代器負責廣播、資料型別轉換和緩衝,同時將內部迴圈交給 Cython 處理。

舉個例子,我們將建立一個平方和函式。首先,讓我們在簡單的 Python 中實現這個函式。我們想要支援一個類似於 numpy sum 函式的‘axis’引數,因此我們需要為op_axes引數構建一個列表。這是看起來的樣子。

例子

>>> def axis_to_axeslist(axis, ndim):
...     if axis is None:
...         return [-1] * ndim
...     else:
...         if type(axis) is not tuple:
...             axis = (axis,)
...         axeslist = [1] * ndim
...         for i in axis:
...             axeslist[i] = -1
...         ax = 0
...         for i in range(ndim):
...             if axeslist[i] != -1:
...                 axeslist[i] = ax
...                 ax += 1
...         return axeslist
...
>>> def sum_squares_py(arr, axis=None, out=None):
...     axeslist = axis_to_axeslist(axis, arr.ndim)
...     it = np.nditer([arr, out], flags=['reduce_ok',
...                                       'buffered', 'delay_bufalloc'],
...                 op_flags=[['readonly'], ['readwrite', 'allocate']],
...                 op_axes=[None, axeslist],
...                 op_dtypes=['float64', 'float64'])
...     with it:
...         it.operands[1][...] = 0
...         it.reset()
...         for x, y in it:
...             y[...] += x*x
...         return it.operands[1]
...
>>> a = np.arange(6).reshape(2,3)
>>> sum_squares_py(a)
array(55.)
>>> sum_squares_py(a, axis=-1)
array([  5.,  50.]) 

要將這個函式 Cython 化,我們將內部迴圈(y[…] += x*x)替換為針對 float64 資料型別專門化的 Cython 程式碼。啟用‘external_loop’標誌後,提供給內部迴圈的陣列將始終是一維的,因此幾乎不需要進行太多的檢查。

這是 sum_squares.pyx 的程式碼清單:

import numpy as np
cimport numpy as np
cimport cython

def axis_to_axeslist(axis, ndim):
    if axis is None:
        return [-1] * ndim
    else:
        if type(axis) is not tuple:
            axis = (axis,)
        axeslist = [1] * ndim
        for i in axis:
            axeslist[i] = -1
        ax = 0
        for i in range(ndim):
            if axeslist[i] != -1:
                axeslist[i] = ax
                ax += 1
        return axeslist

@cython.boundscheck(False)
def sum_squares_cy(arr, axis=None, out=None):
    cdef np.ndarray[double] x
    cdef np.ndarray[double] y
    cdef int size
    cdef double value

    axeslist = axis_to_axeslist(axis, arr.ndim)
    it = np.nditer([arr, out], flags=['reduce_ok', 'external_loop',
                                      'buffered', 'delay_bufalloc'],
                op_flags=[['readonly'], ['readwrite', 'allocate']],
                op_axes=[None, axeslist],
                op_dtypes=['float64', 'float64'])
    with it:
        it.operands[1][...] = 0
        it.reset()
        for xarr, yarr in it:
            x = xarr
            y = yarr
            size = x.shape[0]
            for i in range(size):
               value = x[i]
               y[i] = y[i] + value * value
        return it.operands[1] 

在這臺機器上,將 .pyx 檔案構建為一個模組如下,但你可能需要找一些 Cython 教程來告訴你係統配置的具體情況。:

$ cython sum_squares.pyx
$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -I/usr/include/python2.7 -fno-strict-aliasing -o sum_squares.so sum_squares.c 

從 Python 直譯器執行這個函式會產生與我們原生的 Python/NumPy 程式碼相同的答案。

例子

>>> from sum_squares import sum_squares_cy 
>>> a = np.arange(6).reshape(2,3)
>>> sum_squares_cy(a) 
array(55.0)
>>> sum_squares_cy(a, axis=-1) 
array([  5.,  50.]) 

在 IPython 中進行一點時間測試顯示,Cython 內部迴圈減少的開銷和記憶體分配為我們提供了一個非常好的加速效果,比起直接的 Python 程式碼和使用 NumPy 內建的求和函式表示式要好得多。

>>> a = np.random.rand(1000,1000)

>>> timeit sum_squares_py(a, axis=-1)
10 loops, best of 3: 37.1 ms per loop

>>> timeit np.sum(a*a, axis=-1)
10 loops, best of 3: 20.9 ms per loop

>>> timeit sum_squares_cy(a, axis=-1)
100 loops, best of 3: 11.8 ms per loop

>>> np.all(sum_squares_cy(a, axis=-1) == np.sum(a*a, axis=-1))
True

>>> np.all(sum_squares_py(a, axis=-1) == np.sum(a*a, axis=-1))
True 

單個陣列迭代

使用nditer可以完成的最基本任務是訪問陣列的每個元素。使用標準的 Python 迭代器介面,每個元素會逐個提供。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a):
...     print(x, end=' ')
...
0 1 2 3 4 5 

對於這種迭代,需要注意的一點是迭代順序是選擇與陣列的記憶體佈局匹配,而不是使用標準的 C 或 Fortran 順序。這樣做是為了提高訪問效率,反映了預設情況下,簡單地希望訪問每個元素而不關注特定的順序的想法。我們可以透過迭代我們上一個陣列的轉置來看到這一點,與以 C 順序複製該轉置的方式進行比較。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a.T):
...     print(x, end=' ')
...
0 1 2 3 4 5 
>>> for x in np.nditer(a.T.copy(order='C')):
...     print(x, end=' ')
...
0 3 1 4 2 5 

aa.T的元素以相同的順序遍歷,即它們在記憶體中儲存的順序,而a.T.copy(order='C')的元素以不同的順序訪問,因為它們已經被放置在不同的記憶體佈局中。

控制迭代順序

有時候,重要的是按照特定的順序訪問陣列的元素,而不論記憶體中元素的佈局如何。nditer物件提供了一個order引數來控制迭代的這個方面。預設情況下,該引數的行為如上所述,為 order='K',保持現有順序。可以使用 order='C'來強制使用 C 順序,order='F'來強制使用 Fortran 順序。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, order='F'):
...     print(x, end=' ')
...
0 3 1 4 2 5
>>> for x in np.nditer(a.T, order='C'):
...     print(x, end=' ')
...
0 3 1 4 2 5 

修改陣列值

預設情況下,nditer將輸入運算元視為只讀物件。要能夠修改陣列元素,必須使用‘readwrite’‘writeonly’的每個運算元標誌指定讀寫或只寫模式。

nditer 將產生可寫入的緩衝陣列,您可以修改這些陣列。然而,由於 nditer 必須在迭代結束時將該緩衝區資料複製回原始陣列,因此您必須在迭代結束時發出訊號,可以採用以下兩種方法之一。可以選擇:

  • 當使用with語句將nditer作為上下文管理器時,臨時資料將在退出上下文時寫回。
  • 迭代結束後,呼叫迭代器的close方法,將觸發寫回。

一旦呼叫close或退出上下文,nditer將無法再迭代。

示例

>>> a = np.arange(6).reshape(2,3)
>>> a
array([[0, 1, 2],
 [3, 4, 5]])
>>> with np.nditer(a, op_flags=['readwrite']) as it:
...    for x in it:
...        x[...] = 2 * x
...
>>> a
array([[ 0,  2,  4],
 [ 6,  8, 10]]) 

如果你正在編寫需要支援舊版本 numpy 的程式碼,請注意在 1.15 之前,nditer不是上下文管理器,也沒有close方法。相反,它依賴於解構函式來啟動緩衝區的寫回。

使用外部迴圈

到目前為止的所有示例中,迭代器一次只提供一個元素,因為所有迴圈邏輯都是迭代器內部的。雖然這很簡單和方便,但效率不高。更好的方法是將一維最內層迴圈移到你的程式碼中,外部超過迭代器。這樣,NumPy 的向量化操作可以用於正在訪問的元素的更大塊。

nditer將嘗試為內部迴圈提供儘可能大的塊。強制使用‘C’和‘F’順序時,我們得到不同的外部迴圈大小。可以透過指定迭代器標誌來啟用此模式。

注意,預設保留本機記憶體順序,迭代器能夠提供單個一維塊,而強制 Fortran 順序時,它必須提供三個每個兩個元素的塊。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop']):
...     print(x, end=' ')
...
[0 1 2 3 4 5] 
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 

跟蹤索引或多索引

在迭代過程中,您可能希望在計算中使用當前元素的索引。例如,您可能希望以記憶體順序訪問陣列的元素,但使用 C 順序、Fortran 順序或多維索引來查詢不同陣列中的值。

索引由迭代器物件本身跟蹤,並透過indexmulti_index屬性訪問,具體取決於所請求的內容。下面的示例顯示了列印輸出,用於演示索引的變化:

示例

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> for x in it:
...     print("%d <%d>" % (x, it.index), end=' ')
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> for x in it:
...     print("%d <%s>" % (x, it.multi_index), end=' ')
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     for x in it:
...         x[...] = it.multi_index[1] - it.multi_index[0]
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

跟蹤索引或多索引與使用外部迴圈不相容,因為每個元素需要不同的索引值。如果嘗試結合這些標誌,nditer物件將引發異常。

示例

>>> a = np.zeros((2,3))
>>> it = np.nditer(a, flags=['c_index', 'external_loop'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Iterator flag EXTERNAL_LOOP cannot be used if an index or multi-index is being tracked 

替代迴圈和元素訪問

為了在迭代過程中更容易地使用其屬性,nditer具有一種替代語法,可以顯式地使用迭代器物件本身進行迭代。使用這種迴圈結構,可以透過對迭代器進行索引來訪問當前值。其他屬性,如跟蹤的索引與之前一樣。下面的示例產生與前一節中相同的結果。

示例

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> while not it.finished:
...     print("%d <%d>" % (it[0], it.index), end=' ')
...     is_not_finished = it.iternext()
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> while not it.finished:
...     print("%d <%s>" % (it[0], it.multi_index), end=' ')
...     is_not_finished = it.iternext()
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     while not it.finished:
...         it[0] = it.multi_index[1] - it.multi_index[0]
...         is_not_finished = it.iternext()
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

緩衝陣列元素

在強制迭代順序時,我們觀察到外部迴圈選項可能會以較小的塊提供元素,因為元素不能以恆定的步長以恰當的順序訪問。在編寫 C 程式碼時,這通常沒問題,然而在純 Python 程式碼中,這可能會導致效能顯著下降。

透過啟用緩衝模式,迭代器傳遞給內部迴圈的塊可以更大,大大減少了 Python 直譯器的開銷。在例子中強制 Fortran 迭代順序時,啟用緩衝時,內部迴圈可以一次性看到所有元素。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 
>>> for x in np.nditer(a, flags=['external_loop','buffered'], order='F'):
...     print(x, end=' ')
...
[0 3 1 4 2 5] 

作為特定資料型別迭代

有時候需要將陣列視為與其儲存的不同資料型別。例如,即使被操作的陣列是 32 位浮點數,可以要求在所有計算中都使用 64 位浮點數進行。除非編寫低階 C 程式碼,通常最好讓迭代器處理複製或緩衝,而不是在內部迴圈中自己進行資料型別轉換。

有兩種機制可以實現這個目標,即臨時複製和緩衝模式。使用臨時複製,會使用新的資料型別建立整個陣列的副本,然後對副本進行迭代。在所有迭代完成後,可以透過一種模式對原始陣列進行寫入訪問。臨時複製的主要缺點是,如果迭代資料型別的 itemsize 大於原始資料型別的 itemsize,臨時複製可能會消耗大量記憶體。

緩衝模式可以減少記憶體使用,並且比臨時複製更加高效。除了一些特殊情況,例如在迭代器外部需要使用整個陣列時,建議使用緩衝模式代替臨時複製。在 NumPy 中,緩衝模式被 ufuncs 和其他函式用於支援靈活輸入,並且記憶體開銷很小。

在我們的示例中,我們將使用複雜資料型別處理輸入陣列,以便我們可以對負數進行平方根運算。如果不啟用複製或緩衝模式,迭代器將在資料型別不精確匹配時引發異常。

示例

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand required copying or buffering, but neither copying nor buffering was enabled 

在複製模式下,可以透過每個運算元的標誌“copy”來指定。這樣可以提供按運算元的方式進行控制。緩衝模式可以透過一個迭代器標誌來指定。

示例

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_flags=['readonly','copy'],
...                 op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 

迭代器使用 NumPy 的型別轉換規則來確定是否允許特定的轉換。預設情況下,它實施“safe”型別轉換。這意味著,例如,如果嘗試將 64 位浮點陣列視為 32 位浮點陣列,它將引發異常。在許多情況下,“same_kind”規則是最合理的規則,因為它允許從 64 位轉換為 32 位浮點數,但不允許從浮點數轉換為整數或從複數轉換為浮點數。

示例

>>> a = np.arange(6.)
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32']):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('float32') according to the rule 'safe' 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32'],
...                 casting='same_kind'):
...     print(x, end=' ')
...
0.0 1.0 2.0 3.0 4.0 5.0 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['int32'], casting='same_kind'):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('int32') according to the rule 'same_kind' 

使用讀寫或只寫運算元進行轉換回原始資料型別時需注意。常見的情況是使用 64 位浮點數實現內部迴圈,並使用“same_kind”型別轉換以便處理其他浮點數型別。雖然在只讀模式下可以提供整數陣列,但在讀寫模式下將引發異常,因為轉換回陣列將違反型別轉換規則。

示例

>>> a = np.arange(6)
>>> for x in np.nditer(a, flags=['buffered'], op_flags=['readwrite'],
...                 op_dtypes=['float64'], casting='same_kind'):
...     x[...] = x / 2.0
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: Iterator requested dtype could not be cast from dtype('float64') to dtype('int64'), the operand 0 dtype, according to the rule 'same_kind' 

控制迭代順序

有時重要的是以特定順序訪問陣列的元素,不管元素在記憶體中的佈局如何。nditer 物件提供了一個order引數來控制迭代的這個方面。預設情況下,保持上述行為的是 order=’K’以保持現有順序。可以用 order=’C’覆蓋為 C 順序和 order=’F’為 Fortran 順序。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, order='F'):
...     print(x, end=' ')
...
0 3 1 4 2 5
>>> for x in np.nditer(a.T, order='C'):
...     print(x, end=' ')
...
0 3 1 4 2 5 

修改陣列值

預設情況下,nditer 將輸入運算元視為只讀物件。要能夠修改陣列元素,必須使用‘readwrite’‘writeonly’逐運算元標誌指定讀寫或僅寫模式。

然後 nditer 將生成可寫入的緩衝區陣列,您可以修改。然而,由於 nditer 在迭代結束後必須將此緩衝區資料複製回原始陣列,因此必須透過兩種方法之一來訊號迭代結束。您可以:

  • 使用with語句將 nditer 作為上下文管理器使用,並且在退出上下文時將臨時資料寫回。
  • 在迭代完成後呼叫迭代器的close方法,這將觸發寫回。

一旦呼叫close或退出其上下文,nditer 將不再可迭代。

示例

>>> a = np.arange(6).reshape(2,3)
>>> a
array([[0, 1, 2],
 [3, 4, 5]])
>>> with np.nditer(a, op_flags=['readwrite']) as it:
...    for x in it:
...        x[...] = 2 * x
...
>>> a
array([[ 0,  2,  4],
 [ 6,  8, 10]]) 

如果您正在編寫需要支援較舊版本的 numpy 的程式碼,請注意,在 1.15 之前,nditer 不是上下文管理器,也沒有close方法。相反,它依賴解構函式來啟動緩衝區的寫回。

使用外部迴圈

到目前為止,所有示例中,a 中的元素都是由迭代器逐個提供的,因為所有迴圈邏輯都是迭代器內部的。雖然這種方法簡單方便,但並不是很高效。更好的方法是將一維的內部迴圈移動到您的程式碼中,即在迭代器外部。這樣,NumPy 的向量化操作可以用於正在訪問的元素的更大塊。

nditer 將嘗試提供儘可能大的塊給內部迴圈。透過強制‘C’和‘F’順序,我們得到不同的外部迴圈大小。透過指定迭代器標誌來啟用此模式。

請注意,保持本機記憶體順序的預設設定下,迭代器可以提供一個單一的一維塊,而當強制 Fortran 順序時,它必須提供三個每個兩個元素的塊。

示例

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop']):
...     print(x, end=' ')
...
[0 1 2 3 4 5] 
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 

跟蹤一個索引或多維索引

在迭代過程中,您可能希望在計算中使用當前元素的索引。例如,您可能希望按記憶體順序訪問陣列的元素,但使用 C 順序、Fortran 順序或多維索引來查詢不同陣列中的值。

索引由迭代器物件本身跟蹤,並可以透過 indexmulti_index 屬性訪問,具體取決於所請求的內容。下面的示例展示了列印輸出,以演示索引的進展情況:

例子

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> for x in it:
...     print("%d <%d>" % (x, it.index), end=' ')
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> for x in it:
...     print("%d <%s>" % (x, it.multi_index), end=' ')
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     for x in it:
...         x[...] = it.multi_index[1] - it.multi_index[0]
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

跟蹤索引或多索引不相容於使用外部迴圈,因為它需要每個元素一個不同的索引值。如果嘗試結合這些標誌,則nditer物件將引發異常。

例子

>>> a = np.zeros((2,3))
>>> it = np.nditer(a, flags=['c_index', 'external_loop'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Iterator flag EXTERNAL_LOOP cannot be used if an index or multi-index is being tracked 

替代迴圈和元素訪問

為了在迭代過程中更容易訪問其屬性,nditer提供了另一種迭代的語法,它直接與迭代器物件本身一起工作。使用這種迴圈結構,可以透過對迭代器進行索引來訪問當前值。其他屬性,如跟蹤的索引,保持不變。下面的示例生成了與前一節中相同的結果。

例子

>>> a = np.arange(6).reshape(2,3)
>>> it = np.nditer(a, flags=['f_index'])
>>> while not it.finished:
...     print("%d <%d>" % (it[0], it.index), end=' ')
...     is_not_finished = it.iternext()
...
0 <0> 1 <2> 2 <4> 3 <1> 4 <3> 5 <5> 
>>> it = np.nditer(a, flags=['multi_index'])
>>> while not it.finished:
...     print("%d <%s>" % (it[0], it.multi_index), end=' ')
...     is_not_finished = it.iternext()
...
0 <(0, 0)> 1 <(0, 1)> 2 <(0, 2)> 3 <(1, 0)> 4 <(1, 1)> 5 <(1, 2)> 
>>> with np.nditer(a, flags=['multi_index'], op_flags=['writeonly']) as it:
...     while not it.finished:
...         it[0] = it.multi_index[1] - it.multi_index[0]
...         is_not_finished = it.iternext()
...
>>> a
array([[ 0,  1,  2],
 [-1,  0,  1]]) 

緩衝陣列元素

在強制迭代順序時,我們觀察到外迴圈選項可能會以較小的塊提供元素,因為元素不能以恆定的步幅按適當的順序訪問。在編寫 C 程式碼時,這通常沒問題,但在純 Python 程式碼中,這可能會導致效能顯著下降。

透過啟用緩衝模式,可以使迭代器提供給內迴圈的塊變得更大,從而顯著降低 Python 直譯器的開銷。例如,強制使用 Fortran 迭代順序時,當啟用緩衝時,內迴圈可以一次性看到所有元素。

例子

>>> a = np.arange(6).reshape(2,3)
>>> for x in np.nditer(a, flags=['external_loop'], order='F'):
...     print(x, end=' ')
...
[0 3] [1 4] [2 5] 
>>> for x in np.nditer(a, flags=['external_loop','buffered'], order='F'):
...     print(x, end=' ')
...
[0 3 1 4 2 5] 

作為特定資料型別進行迭代

有時需要將陣列視為儲存時的不同資料型別。例如,即使被操作的陣列是 32 位浮點數,也可能希望在 64 位浮點數上進行所有計算。除了編寫低階 C 程式碼時,通常最好讓迭代器處理複製或緩衝,而不是在內部迴圈中自己轉換資料型別。

有兩種機制可以實現這個目標,即臨時副本和緩衝模式。使用臨時副本時,會對整個陣列進行新資料型別的複製,然後在副本上進行迭代。在迭代完成後,可以透過一種更新原陣列的模式進行寫入。臨時副本的主要缺點在於,如果迭代資料型別的 itemsize 大於原始資料型別,臨時副本可能會消耗大量記憶體。

緩衝模式緩解了記憶體使用問題,並且比製作臨時副本更符合快取的工作方式。除了一些特殊情況,需要在迭代器之外一次性使用整個陣列時,建議使用緩衝而不是臨時複製。在 NumPy 中,ufuncs 和其他函式使用緩衝支援具有最小記憶體開銷的靈活輸入。

在我們的例子中,我們將處理具有複雜資料型別的輸入陣列,以便我們可以對負數取平方根。如果資料型別不精確匹配,迭代器將在不啟用複製或緩衝模式時引發異常。

例子

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand required copying or buffering, but neither copying nor buffering was enabled 

在複製模式中,‘copy’被指定為每個運算元的標誌。這樣做是為了以每個運算元的方式來提供控制。緩衝模式被指定為迭代器標誌。

例子

>>> a = np.arange(6).reshape(2,3) - 3
>>> for x in np.nditer(a, op_flags=['readonly','copy'],
...                 op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']):
...     print(np.sqrt(x), end=' ')
...
1.7320508075688772j 1.4142135623730951j 1j 0j (1+0j) (1.4142135623730951+0j) 

迭代器使用 NumPy 的轉換規則來確定特定轉換是否被允許。預設情況下,它執行‘safe’轉換。這意味著,例如,如果嘗試將 64 位浮點陣列視為 32 位浮點陣列,它會引發異常。在許多情況下,‘same_kind’規則是最合理的規則,因為它允許從 64 位轉換為 32 位浮點,但不允許從浮點轉換為整數或從複數轉換為浮點。

例子

>>> a = np.arange(6.)
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32']):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('float32') according to the rule 'safe' 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['float32'],
...                 casting='same_kind'):
...     print(x, end=' ')
...
0.0 1.0 2.0 3.0 4.0 5.0 
>>> for x in np.nditer(a, flags=['buffered'], op_dtypes=['int32'], casting='same_kind'):
...     print(x, end=' ')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Iterator operand 0 dtype could not be cast from dtype('float64') to dtype('int32') according to the rule 'same_kind' 

要注意的一點是當使用可讀寫或僅寫入運算元時,將資料型別轉換回原始資料型別。一個常見情況是根據 64 位浮點實現內部迴圈,並使用‘same_kind’轉換來允許處理其他浮點型別。在只讀模式下,可以提供一個整數陣列,而在讀寫模式下,將引發異常,因為轉換回陣列將違反轉換規則。

例子

>>> a = np.arange(6)
>>> for x in np.nditer(a, flags=['buffered'], op_flags=['readwrite'],
...                 op_dtypes=['float64'], casting='same_kind'):
...     x[...] = x / 2.0
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: Iterator requested dtype could not be cast from dtype('float64') to dtype('int64'), the operand 0 dtype, according to the rule 'same_kind' 

廣播陣列迭代

NumPy 有一組規則來處理具有不同形狀的陣列,這些規則適用於函式接受多個運算元並進行逐元素結合時。這被稱為廣播。當需要編寫這樣一個函式時,nditer 物件可以為您應用這些規則。

舉個例子,我們列印出將一維和二維陣列進行廣播的結果。

例子

>>> a = np.arange(3)
>>> b = np.arange(6).reshape(2,3)
>>> for x, y in np.nditer([a,b]):
...     print("%d:%d" % (x,y), end=' ')
...
0:0 1:1 2:2 0:3 1:4 2:5 

當發生廣播錯誤時,迭代器會引發異常,其中包含輸入形狀以幫助診斷問題。

例子

>>> a = np.arange(2)
>>> b = np.arange(6).reshape(2,3)
>>> for x, y in np.nditer([a,b]):
...     print("%d:%d" % (x,y), end=' ')
...
Traceback (most recent call last):
...
ValueError: operands could not be broadcast together with shapes (2,) (2,3) 

迭代器分配的輸出陣列

在 NumPy 函式中的一個常見情況是根據輸入的廣播分配輸出,並且還有一個可選引數稱為 ‘out’,為提供結果時提供位置。nditer物件提供了一個方便的習語,使得支援這一機制變得非常容易。

透過建立一個名為square的函式來展示它是如何工作的,該函式的作用是對輸入進行平方。讓我們從一個最簡的函式定義開始,不包括‘out’引數支援。

例子

>>> def square(a):
...     with np.nditer([a, None]) as it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
...
>>> square([1,2,3])
array([1, 4, 9]) 

預設情況下,nditer 對傳入的 None 作為運算元使用‘allocate’和‘writeonly’標誌。這意味著我們只需為迭代器提供這兩個運算元,它會處理其餘的。

當新增“out”引數時,我們必須明確提供這些標誌,因為如果有人將陣列作為“out”傳入,則迭代器將預設為“readonly”,我們的內部迴圈將失敗。 “readonly” 是輸入陣列的預設值的原因是為了防止意外觸發縮減操作而引起混淆。 如果預設值為“readwrite”,任何廣播操作也將觸發縮減操作,這是本文件後面將涉及的一個主題。

在此之際,讓我們也引入“no_broadcast”標誌,這將阻止輸出進行廣播。 這很重要,因為我們只想要每個輸出一個輸入值。 聚合多個輸入值是一個需要特殊處理的縮減操作。 它已經會引發錯誤,因為縮減必須在迭代器標誌中明確啟用,但是由於禁用廣播而產生的錯誤訊息對終端使用者來說更容易理解。 要了解如何將平方函式推廣到縮減,請檢視有關 Cython 部分中的平方和函式。

為了完整起見,我們還將新增“external_loop”和“buffered”標誌,因為出於效能原因,這通常是您所需要的。

示例

>>> def square(a, out=None):
...     it = np.nditer([a, out],
...             flags = ['external_loop', 'buffered'],
...             op_flags = [['readonly'],
...                         ['writeonly', 'allocate', 'no_broadcast']])
...     with it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
... 
>>> square([1,2,3])
array([1, 4, 9]) 
>>> b = np.zeros((3,))
>>> square([1,2,3], out=b)
array([1.,  4.,  9.])
>>> b
array([1.,  4.,  9.]) 
>>> square(np.arange(6).reshape(2,3), out=b)
Traceback (most recent call last):
  ...
ValueError: non-broadcastable output operand with shape (3,) doesn't
match the broadcast shape (2,3) 

外積迭代

任何二元操作都可以以類似於 outer 中的外積方式擴充套件為陣列操作,並且 nditer 物件透過顯式對映運算元的軸提供了一種實現此目的的方法。 也可以使用 newaxis 索引來完成此操作,但我們將向您展示如何直接使用 nditer 的 op_axes 引數來完成此操作,而無需中間檢視。

我們將執行一個簡單的外積,將第一個運算元的維度放在第二個運算元的維度之前。 op_axes 引數需要每個運算元的一個軸列表,並提供迭代器軸到運算元軸的對映。

假設第一個運算元是一維的,第二個運算元是二維的。 迭代器將有三個維度,因此 op_axes 將有兩個 3 元素列表。 第一個列表選擇第一個運算元的一個軸,並且對於迭代器的其餘軸,它為 -1,最終結果為 [0, -1, -1]。 第二個列表選擇第二個運算元的兩個軸,但不應與第一個運算元中選擇的軸重疊。 其列表為 [-1, 0, 1]。 輸出運算元以標準方式對映到迭代器軸,因此我們可以提供 None 而不是構造另一個列表。

內迴圈中的操作是直接的乘法。 關於外積的所有內容都由迭代器設定處理。

示例

>>> a = np.arange(3)
>>> b = np.arange(8).reshape(2,4)
>>> it = np.nditer([a, b, None], flags=['external_loop'],
...             op_axes=[[0, -1, -1], [-1, 0, 1], None])
>>> with it:
...     for x, y, z in it:
...         z[...] = x*y
...     result = it.operands[2]  # same as z
...
>>> result
array([[[ 0,  0,  0,  0],
 [ 0,  0,  0,  0]],
 [[ 0,  1,  2,  3],
 [ 4,  5,  6,  7]],
 [[ 0,  2,  4,  6],
 [ 8, 10, 12, 14]]]) 

請注意,一旦迭代器被關閉,我們就無法訪問operands,必須使用在上下文管理器中建立的引用。

減少迭代

每當可寫運算元的元素少於完整迭代空間時,該運算元都將經歷一個減少。nditer物件要求任何減少運算元標記為讀寫,並且只允許在提供‘reduce_ok’作為迭代器標誌時進行減少。

舉個簡單的例子,考慮對陣列中所有元素進行求和。

例如

>>> a = np.arange(24).reshape(2,3,4)
>>> b = np.array(0)
>>> with np.nditer([a, b], flags=['reduce_ok'],
...                     op_flags=[['readonly'], ['readwrite']]) as it:
...     for x,y in it:
...         y[...] += x
...
>>> b
array(276)
>>> np.sum(a)
276 

將縮減和分配的運算元組合時會有一些複雜。在開始迭代之前,任何減少運算元都必須被初始化為其開始值。以下是我們如何做到這一點,對a的最後一個軸求和。

例如

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]])
>>> np.sum(a, axis=2)
array([[ 6, 22, 38],
 [54, 70, 86]]) 

要做緩衝減少需要在設定期間進行另一個調整。通常,迭代器構造涉及從可讀陣列中複製資料的第一個緩衝區。任何減少運算元都是可讀取的,因此它可以被讀取到緩衝區中。不幸的是,在這個緩衝操作完成之後初始化運算元不會反映在迭代開始時的緩衝區中,並且將產生垃圾結果。

迭代器標誌“delay_bufalloc”是為了允許迭代器分配的縮減運算元與緩衝存在在一起。當設定了這個標誌時,迭代器將保持其緩衝區未初始化,直到收到重置訊號,之後它將準備好進行常規迭代。如果我們還啟用緩衝,前面的示例將如下所示。

例如

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok',
...                                  'buffered', 'delay_bufalloc'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     it.reset()
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]]) 

迭代器分配的輸出陣列

在 NumPy 函式中的一個常見情況是,根據輸入的廣播來分配輸出,並且還有一個名為‘out’的可選引數,在提供結果時將其放置在那裡。nditer物件提供了一個方便的習語,使得支援這種機制非常容易。

我們將透過建立一個函式square來展示這是如何工作的,它會對其輸入進行平方操作。讓我們從一個排除‘out’引數支援的最小函式定義開始。

例如

>>> def square(a):
...     with np.nditer([a, None]) as it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
...
>>> square([1,2,3])
array([1, 4, 9]) 

預設情況下,nditer對於以 None 傳入的運算元使用了‘allocate’和‘writeonly’標誌。這意味著我們只需向迭代器提供兩個運算元,剩下的交給它處理。

當新增‘out’引數時,必須明確提供這些標誌,因為如果有人將陣列傳遞給‘out’,迭代器將預設為‘readonly’,而我們的內部迴圈將失敗。輸入陣列的預設值為‘readonly’是為了防止意外觸發減少操作產生混淆。如果預設值是‘readwrite’,任何廣播操作也會觸發減少操作,這個主題稍後在本文件中討論。

在這個過程中,讓我們也介紹‘no_broadcast’標誌,它將阻止輸出被廣播。這很重要,因為我們只想要每個輸出一個輸入值。聚合多於一個輸入值是一個需要特殊處理的減少操作。儘管因為減少操作必須在迭代器標誌中顯式啟用,這會引發錯誤,但禁用廣播導致的錯誤訊息對終端使用者來說更容易理解。要了解如何將平方函式推廣為減少函式,請參閱有關 Cython 的平方和函式的部分。

為了完整起見,我們還將新增‘external_loop’和‘buffered’標誌,因為這通常是出於效能原因。

例子

>>> def square(a, out=None):
...     it = np.nditer([a, out],
...             flags = ['external_loop', 'buffered'],
...             op_flags = [['readonly'],
...                         ['writeonly', 'allocate', 'no_broadcast']])
...     with it:
...         for x, y in it:
...             y[...] = x*x
...         return it.operands[1]
... 
>>> square([1,2,3])
array([1, 4, 9]) 
>>> b = np.zeros((3,))
>>> square([1,2,3], out=b)
array([1.,  4.,  9.])
>>> b
array([1.,  4.,  9.]) 
>>> square(np.arange(6).reshape(2,3), out=b)
Traceback (most recent call last):
  ...
ValueError: non-broadcastable output operand with shape (3,) doesn't
match the broadcast shape (2,3) 

外部積迭代

任何二進位制操作都可以像outer中那樣以外部積方式擴充套件為陣列操作,而nditer物件透過顯式對映運算元的軸提供了一種方法。還可以透過newaxis索引來做到這一點,但我們將向您展示如何直接使用 nditer 的 op_axes 引數來實現這一點,而不需要中間檢視。

我們將進行一個簡單的外部積,將第一個運算元的維度放在第二個運算元的維度之前。op_axes 引數需要為每個運算元提供一個軸列表,並且提供了一個從迭代器的軸到運算元的軸的對映。

假設第一個運算元是一維的,而第二個運算元是二維的。迭代器將有三個維度,因此 op_axes 將有兩個包含三個元素的列表。第一個列表選擇第一個運算元的一個軸,並且對於迭代器的其他軸,為-1,最終結果是[0,-1,-1]。第二個列表選擇第二個運算元的兩個軸,但不應與第一個運算元選擇的軸重疊。它的列表是[-1,0,1]。輸出運算元以標準方式對映到迭代器軸,因此我們可以使用 None 代替構造另一個列表。

內迴圈中的操作是直接的乘法。與外部積有關的所有事情都由迭代器設定處理。

例子

>>> a = np.arange(3)
>>> b = np.arange(8).reshape(2,4)
>>> it = np.nditer([a, b, None], flags=['external_loop'],
...             op_axes=[[0, -1, -1], [-1, 0, 1], None])
>>> with it:
...     for x, y, z in it:
...         z[...] = x*y
...     result = it.operands[2]  # same as z
...
>>> result
array([[[ 0,  0,  0,  0],
 [ 0,  0,  0,  0]],
 [[ 0,  1,  2,  3],
 [ 4,  5,  6,  7]],
 [[ 0,  2,  4,  6],
 [ 8, 10, 12, 14]]]) 

請注意,一旦迭代器關閉,我們就無法訪問 operands ,必須使用在上下文管理器內建立的引用。

歸約迭代

每當可寫運算元的元素少於完整迭代空間時,該運算元正在進行歸約。 nditer 物件要求任何歸約運算元都必須標記為讀寫,只有在提供“reduce_ok”作為迭代器標誌時才允許進行歸約。

舉個簡單的例子,考慮對陣列中所有元素求和。

示例

>>> a = np.arange(24).reshape(2,3,4)
>>> b = np.array(0)
>>> with np.nditer([a, b], flags=['reduce_ok'],
...                     op_flags=[['readonly'], ['readwrite']]) as it:
...     for x,y in it:
...         y[...] += x
...
>>> b
array(276)
>>> np.sum(a)
276 

在合併歸約和分配運算元時,事情變得有些棘手。在啟動迭代之前,任何歸約運算元都必須初始化為其起始值。這是我們如何做到這一點的,沿著 a 的最後一個軸求和。

示例

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]])
>>> np.sum(a, axis=2)
array([[ 6, 22, 38],
 [54, 70, 86]]) 

要進行緩衝歸約需要在設定過程中進行另一個調整。通常,迭代器構建涉及將可讀陣列的第一個緩衝區資料複製到緩衝區中。任何歸約運算元都是可讀的,因此可能會被讀入緩衝區。不幸的是,在此緩衝操作完成後初始化運算元不會反映在迭代開始時的緩衝區中,將產生垃圾結果。

迭代器標誌“delay_bufalloc”允許迭代器分配的歸約運算元與緩衝存在在一起。設定此標誌後,迭代器將保持其緩衝區未初始化,直到收到重置之後,才會準備好進行常規迭代。如果我們還啟用緩衝,前面的例子將如何呈現。

示例

>>> a = np.arange(24).reshape(2,3,4)
>>> it = np.nditer([a, None], flags=['reduce_ok',
...                                  'buffered', 'delay_bufalloc'],
...             op_flags=[['readonly'], ['readwrite', 'allocate']],
...             op_axes=[None, [0,1,-1]])
>>> with it:
...     it.operands[1][...] = 0
...     it.reset()
...     for x, y in it:
...         y[...] += x
...     result = it.operands[1]
...
>>> result
array([[ 6, 22, 38],
 [54, 70, 86]]) 

將內部迴圈放入 Cython 中

那些希望在低階操作中獲得非常好效能的人應該認真考慮直接使用 C 中提供的迭代 API,但對於那些不熟悉 C 或 C++ 的人來說,Cython 是一個效能合理的好中間地帶。對於 nditer 物件來說,這意味著讓迭代器處理廣播、資料型別轉換和緩衝,同時將內部迴圈交給 Cython。

對於我們的示例,我們將建立一個求平方和的函式。首先,讓我們在直接的 Python 中實現這個函式。我們想支援類似於 numpy sum 函式的 'axis' 引數,因此我們需要為 op_axes 引數構造一個列表。這是實現的方式。

示例

>>> def axis_to_axeslist(axis, ndim):
...     if axis is None:
...         return [-1] * ndim
...     else:
...         if type(axis) is not tuple:
...             axis = (axis,)
...         axeslist = [1] * ndim
...         for i in axis:
...             axeslist[i] = -1
...         ax = 0
...         for i in range(ndim):
...             if axeslist[i] != -1:
...                 axeslist[i] = ax
...                 ax += 1
...         return axeslist
...
>>> def sum_squares_py(arr, axis=None, out=None):
...     axeslist = axis_to_axeslist(axis, arr.ndim)
...     it = np.nditer([arr, out], flags=['reduce_ok',
...                                       'buffered', 'delay_bufalloc'],
...                 op_flags=[['readonly'], ['readwrite', 'allocate']],
...                 op_axes=[None, axeslist],
...                 op_dtypes=['float64', 'float64'])
...     with it:
...         it.operands[1][...] = 0
...         it.reset()
...         for x, y in it:
...             y[...] += x*x
...         return it.operands[1]
...
>>> a = np.arange(6).reshape(2,3)
>>> sum_squares_py(a)
array(55.)
>>> sum_squares_py(a, axis=-1)
array([  5.,  50.]) 

要將此函式進行 Cython-化,我們用針對 float64 資料型別專門設計的 Cython 程式碼替換內部迴圈(y […] += x*x)。啟用 'external_loop' 標誌後,提供給內部迴圈的陣列始終是一維的,因此很少需要進行檢查。

這裡是 sum_squares.pyx 的程式碼清單:

import numpy as np
cimport numpy as np
cimport cython

def axis_to_axeslist(axis, ndim):
    if axis is None:
        return [-1] * ndim
    else:
        if type(axis) is not tuple:
            axis = (axis,)
        axeslist = [1] * ndim
        for i in axis:
            axeslist[i] = -1
        ax = 0
        for i in range(ndim):
            if axeslist[i] != -1:
                axeslist[i] = ax
                ax += 1
        return axeslist

@cython.boundscheck(False)
def sum_squares_cy(arr, axis=None, out=None):
    cdef np.ndarray[double] x
    cdef np.ndarray[double] y
    cdef int size
    cdef double value

    axeslist = axis_to_axeslist(axis, arr.ndim)
    it = np.nditer([arr, out], flags=['reduce_ok', 'external_loop',
                                      'buffered', 'delay_bufalloc'],
                op_flags=[['readonly'], ['readwrite', 'allocate']],
                op_axes=[None, axeslist],
                op_dtypes=['float64', 'float64'])
    with it:
        it.operands[1][...] = 0
        it.reset()
        for xarr, yarr in it:
            x = xarr
            y = yarr
            size = x.shape[0]
            for i in range(size):
               value = x[i]
               y[i] = y[i] + value * value
        return it.operands[1] 

在這臺機器上,將 .pyx 檔案構建為一個模組看起來像下面這樣,但是你可能需要找一些 Cython 教程來告訴你係統配置的具體資訊。:

$ cython sum_squares.pyx
$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -I/usr/include/python2.7 -fno-strict-aliasing -o sum_squares.so sum_squares.c 

從 Python 直譯器中執行這段程式碼會產生與我們本地 Python/NumPy 程式碼相同的答案。

例子

>>> from sum_squares import sum_squares_cy 
>>> a = np.arange(6).reshape(2,3)
>>> sum_squares_cy(a) 
array(55.0)
>>> sum_squares_cy(a, axis=-1) 
array([  5.,  50.]) 

在 IPython 中進行一點計時顯示,Cython 內迴圈的減少開銷和記憶體分配提供了對直接 Python 程式碼和使用 NumPy 內建 sum 函式的表示式都有很好的加速。:

>>> a = np.random.rand(1000,1000)

>>> timeit sum_squares_py(a, axis=-1)
10 loops, best of 3: 37.1 ms per loop

>>> timeit np.sum(a*a, axis=-1)
10 loops, best of 3: 20.9 ms per loop

>>> timeit sum_squares_cy(a, axis=-1)
100 loops, best of 3: 11.8 ms per loop

>>> np.all(sum_squares_cy(a, axis=-1) == np.sum(a*a, axis=-1))
True

>>> np.all(sum_squares_py(a, axis=-1) == np.sum(a*a, axis=-1))
True 

標準陣列子類

原文:numpy.org/doc/1.26/reference/arrays.classes.html

注意

numpy.ndarray 的子類化是可能的,但如果您的目標是建立具有修改行為的陣列,如用於分散式計算的 Dask 陣列和用於基於 GPU 的計算的 CuPy 陣列,不建議子類化。相反,推薦使用 numpy 的排程機制。

可以繼承 ndarray(在 Python 或 C 中)。因此,它可以成為許多有用類的基礎。通常,是子類化陣列物件還是隻是將核心陣列元件作為新類的內部部分的決定是一個困難的決定,只是一種選擇。NumPy 有幾種工具可簡化新物件與其他陣列物件的互動方式,因此最終選擇可能並不重要。簡化問題的一種方式是問自己您感興趣的物件是否可以被單個陣列替換或者是否它的核心真的需要兩個或更多陣列。

請注意,asarray 總是返回基類 ndarray。如果您確信您對陣列物件的使用可以處理 ndarray 的任何子類,那麼 asanyarray 可以用於允許子類更清晰地傳播到您的子例程中。在原則上,子類可以重新定義陣列的任何方面,因此,在嚴格的指導方針下,asanyarray 很少有用。但是,陣列物件的大多數子類不會重新定義陣列物件的某些方面,如緩衝區介面或陣列的屬性。然而,您的子例程可能無法處理陣列的任意子類的一個重要示例是矩陣將“*”運算子重新定義為矩陣乘法,而不是逐元素乘法。

特殊屬性和方法

另見

作為 ndarray 的子類

NumPy 提供了幾個類可以自定義的鉤子:

class.__array_ufunc__(ufunc, method, *inputs, **kwargs)

自版本 1.13 新功能。

任何類、ndarray 子類或非子類都可以定義此方法或將其設定為 None 以覆蓋 NumPy 的 ufunc 的行為。這與 Python 的 __mul__ 和其他二進位制操作例程的工作方式相似。

  • ufunc 是呼叫的 ufunc 物件。

  • method 是指呼叫了哪個 Ufunc 方法的字串("__call__""reduce""reduceat""accumulate""outer""inner"之一)。

  • inputsufunc 的輸入引數的元組。

  • kwargs是一個包含 ufunc 的可選輸入引數的字典。如果提供,任何out引數,無論是位置引數還是關鍵字引數,都作為tuple傳遞給kwargs。有關詳細資訊,請參閱通用函式(ufunc)中的討論。

該方法應該返回操作的結果,或者如果請求的操作未實現,則返回NotImplemented

如果輸入、輸出或where引數中的一個具有__array_ufunc__方法,那麼將執行該方法而不是 ufunc。如果多個引數實現了__array_ufunc__,則按照以下順序嘗試:子類優先於超類,輸入優先於輸出,輸出優先於where,否則從左到右。第一個返回不是NotImplemented的例程確定結果。如果所有的__array_ufunc__操作都返回NotImplemented,則會引發TypeError

注意

我們打算將 numpy 函式重新實現為(廣義的)Ufunc,這樣它們就可以被__array_ufunc__方法覆蓋。一個主要的候選者是matmul,它目前不是一個 Ufunc,但可以相對容易地重寫為(一組)廣義 Ufuncs。與medianaminargsort等功能可能發生相同的情況。

與其他在 Python 中的一些特殊方法,如__hash____iter__一樣,您可以透過設定__array_ufunc__ = None來指示您的類支援 ufuncs。當呼叫在設定了__array_ufunc__ = None的物件上時,ufuncs 總是會引發TypeError

__array_ufunc__的存在還會影響當arr是一個ndarrayobj是自定義類的例項時,ndarray如何處理arr + objarr < 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__方法來實現這一點。(請注意,這意味著編寫一個始終返回NotImplemented__array_ufunc__與設定__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,這可能看起來很意外並令人困惑,因為這樣子類將完全無法與 ufuncs 一起使用)。

  • ndarray定義了自己的__array_ufunc__方法,如果沒有引數被過載,則評估 ufunc,並且否則返回NotImplemented。這對於生成將自身類的任何例項轉換為ndarray的子類可能有用:然後可以使用super().__array_ufunc__(*inputs, **kwargs)將這些傳遞給其超類,最終在可能的反向轉換後返回結果。這種做法的優點在於確保能夠擁有一個擴充套件行為的子類層次結構。請參閱 ndarray 的子類化了解詳情。

注意

如果一個類定義了__array_ufunc__方法,這將禁用 ufuncs 的__array_wrap____array_prepare__、和__array_priority__機制(這些機制可能最終被棄用)。

class.__array_function__(func, types, args, kwargs)

在 1.16 版中新增。

  • func是 NumPy 公共 API 中暴露的任意可呼叫物件,以func(*args, **kwargs)的形式呼叫。

  • types是原始 NumPy 函式呼叫中實現__array_function__的唯一引數型別的集合collections.abc.Collection

  • 元組args和字典kwargs直接從原始呼叫中傳遞。

作為__array_function__實現者的便利,types提供了所有引數型別的'__array_function__'屬性。這使得實現者能夠快速識別出應該將其他引數的處理委託給__array_function__實現的情況。實現不應依賴於types的迭代順序。

大多數__array_function__的實現將以兩個檢查開始:

  1. 給定的函式是否是我們知道如何過載的?

  2. 所有的引數都是我們知道如何處理的型別嗎?

如果滿足這些條件,__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_FUNCTIONSfunc

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引數)。只有在 NumPy 函式呼叫中明確使用了可選引數時,才會將可選引數傳遞給__array_function__

就像內建特殊方法__add__的情況一樣,正確編寫的__array_function__方法在遇到未知型別時應該始終返回NotImplemented。否則,如果操作還包括您的物件之一,則無法正確地覆蓋另一個物件的 NumPy 函式。

在大多數情況下,與__array_ufunc__的排程規則匹配的是__array_function__。特別是:

  • NumPy 將從所有指定的輸入中收集__array_function__的實現,並按順序呼叫它們:子類優先於超類,否則從左到右。請注意,在涉及子類的某些邊緣情況下,這與 Python 的當前行為略有不同。

  • __array_function__的實現指示它們可以處理操作,方法是返回任何值,而不是NotImplemented

  • 如果所有的__array_function__方法都返回NotImplemented,NumPy 將引發TypeError

如果不存在__array_function__方法,NumPy 將預設呼叫其自己的實現,用於 NumPy 陣列。例如,當所有類似陣列的引數都是 Python 數字或列表時,會出現這種情況。(NumPy 陣列確實有一個__array_function__方法,如下所示,但如果除了 NumPy 陣列子類之外的任何引數都實現了__array_function__,它將始終返回NotImplemented。)

__array_ufunc__當前行為的一個偏差是,NumPy 僅會在每種唯一型別的第一個引數上呼叫__array_function__。這符合 Python 的呼叫反射方法的規則,這確保了在存在大量過載引數時檢查過載的效能是可接受的。

class.__array_finalize__(obj)

當系統從objobjndarray的子類(子型別))內部分配新陣列時,將呼叫此方法。它可用於在構造後更改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__ 返回的物件。這種做法會返回TypeError。 ## 矩陣物件

注意

強烈建議使用矩陣子類。如下所述,這使得編寫函式,以一致地處理矩陣和常規陣列變得非常困難。目前,它們主要用於與scipy.sparse的互動。然而,我們希望為這種用法提供一種替代方案,並最終移除matrix子類。

matrix 物件繼承自 ndarray,因此它們具有與 ndarrays 相同的屬性和方法。但是,matrix 物件有六個重要的不同之處,這可能會導致意外的結果,當你使用矩陣時,但期望它們的行為像陣列:

  1. 可以使用字串表示法建立矩陣物件,這樣可以使用 Matlab 風格的語法,空格分隔列,分號(‘;’)分隔行。

  2. 矩陣物件始終是二維的。這有著深遠的意義,因為 m.ravel() 仍然是二維的(在第一維有一個 1),並且條目選擇返回二維物件,因此序列行為與陣列根本不同。

  3. 矩陣物件覆蓋了乘法,成為矩陣乘法。務必要理解這一點,特別是在你希望接受矩陣的函式中。尤其要注意的是,當 m 是一個矩陣時,asanyarray(m) 會返回一個矩陣。

  4. 矩陣物件覆蓋了冪運算,成為矩陣的冪。對於使用 asanyarray(…) 獲取陣列物件的函式中使用冪運算的相同警告,也適用於這一事實。

  5. 矩陣物件的預設 array_priority 是 10.0,因此與 ndarrays 的混合操作始終產生矩陣。

  6. 矩陣具有使計算更簡單的特殊屬性。這些屬性是

    matrix.T 返回矩陣的轉置。
    matrix.H 返回自身的(複數)共軛轉置。
    matrix.I 返回可逆自身的(乘法)逆。
    matrix.A ndarray 物件的形式返回自身

警告

矩陣物件重寫了乘法 * 和冪運算 **,分別用於矩陣乘法和矩陣冪。如果你的子程式可以接受子類而且你沒有轉換為基類陣列,那麼你必須使用 ufuncs 的 multiply 和 power 來確保對所有輸入執行正確的操作。

矩陣類是 ndarray 的 Python 子類,可用作構建自己的 ndarray 子類的參考。矩陣可以從其他矩陣、字串和任何可轉換為 ndarray 的東西建立。名稱“mat”是 NumPy 中“matrix”的別名。

matrix(data[, dtype, copy])

注意

不再建議使用這個類,即使是用於線性

|

asmatrix(data[, dtype]) 將輸入解釋為矩陣。
bmat(obj[, ldict, gdict]) 從字串、巢狀序列或陣列構建一個矩陣物件。

示例 1:從字串建立矩陣

>>> a = np.mat('1 2 3; 4 5 3')
>>> print((a*a.T).I)
 [[ 0.29239766 -0.13450292]
 [-0.13450292  0.08187135]] 

示例 2:從巢狀序列建立矩陣

>>> np.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:從陣列建立矩陣

>>> np.mat(np.random.rand(3,3)).T
matrix([[4.17022005e-01, 3.02332573e-01, 1.86260211e-01],
 [7.20324493e-01, 1.46755891e-01, 3.45560727e-01],
 [1.14374817e-04, 9.23385948e-02, 3.96767474e-01]]) 

記憶體對映檔案陣列

記憶體對映檔案對於讀取和/或修改具有常規佈局的大檔案的小段非常有用,而無需將整個檔案讀入記憶體。ndarray 的一個簡單子類使用記憶體對映檔案作為陣列的資料緩衝區。對於小檔案,將整個檔案讀入記憶體的開銷通常不重要,但對於大檔案,使用記憶體對映可以節省大量資源。

記憶體對映檔案陣列除了繼承自 ndarray 的方法之外,還有一個額外的方法:.flush(),使用者必須手動呼叫該方法以確保陣列的任何更改實際上都被寫入磁碟。

memmap(filename[, dtype, mode, offset, ...]) 建立一個對映到儲存在磁碟上的二進位制檔案中的陣列的記憶體對映。
memmap.flush() 將陣列中的任何更改寫入磁碟上的檔案。

例子:

>>> a = np.memmap('newfile.dat', dtype=float, mode='w+', shape=1000)
>>> a[10] = 10.0
>>> a[30] = 30.0
>>> del a
>>> b = np.fromfile('newfile.dat', dtype=float)
>>> print(b[10], b[30])
10.0 30.0
>>> a = np.memmap('newfile.dat', dtype=float)
>>> print(a[10], a[30])
10.0 30.0 

字元陣列(numpy.char

另請參閱

建立字元陣列(numpy.char)

注意

chararray類是為了向後相容 Numarray 而存在的,不建議用於新的開發。從 numpy 1.4 開始,如果需要字串陣列,建議使用dtype object_bytes_str_的陣列,並使用numpy.char模組中的自由函式進行快速向量化字串操作。

這些陣列是增強型陣列,可以是str_型別或bytes_型別。這些陣列繼承自ndarray,但特別定義了+*%操作,這些操作是以(廣播)元素為基礎的。這些操作在標準的字元型別的ndarray上不可用。此外,chararray具有所有標準的str (和bytes)方法,會在元素基礎上執行它們。也許建立一個 chararray 最簡單的方法是使用self.view(chararray),其中self是一個 str 或 unicode 資料型別的 ndarray。然而,chararray 也可以使用numpy.chararray建構函式,或透過numpy.char.array函式建立:

chararray(shape[, itemsize, unicode, ...]) 為字串和 unicode 值的陣列提供了一個方便的檢視。
core.defchararray.array(obj[, itemsize, ...]) 建立一個chararray

與標準的字串資料型別的 ndarray 的另一個不同之處是,chararray 繼承了 Numarray 引入的特性,即陣列中任何元素末尾的空白將在元素檢索和比較操作中被忽略。

記錄陣列(numpy.rec

參見

建立記錄陣列(numpy.rec),資料型別例程,資料型別物件(dtype)。

NumPy 提供了 recarray 類,允許將結構化陣列的欄位作為屬性訪問,以及相應的標量資料型別物件 record

recarray(shape[, dtype, buf, offset, ...]) 構造一個允許使用屬性進行欄位訪問的 ndarray。
record 允許透過屬性查詢進行欄位訪問的資料型別標量。

掩碼陣列 (numpy.ma)

另見

掩碼陣列

標準容器類

為了向後相容並作為標準的“容器”類,將 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 = next(myiter),直到迭代器引發 StopIteration。有幾種可能有用的陣列迭代方法:預設迭代、平面迭代和 (N)-維列舉。

預設迭代

ndarray 物件的預設迭代器是序列型別的預設 Python 迭代器。因此,當陣列物件本身被用作迭代器時。預設行為相當於:

for i in range(arr.shape[0]):
    val = arr[i] 

此預設迭代器從陣列中選擇一個維度為 (N-1) 的子陣列。這對定義遞迴演算法是一個有用的構造。要迴圈遍歷整個陣列需要 (N) 個 for 迴圈。

>>> a = np.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-D 迭代器。

正如先前提到的,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 

在這裡,我使用內建的 enumerate 迭代器返回迭代器索引以及值。

N 維列舉

ndenumerate(arr) 多維索引迭代器。

有時在迭代時獲取 N 維索引可能很有用。 ndenumerate 迭代器可以實現這一點。

>>> for i, val in np.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 np.broadcast([[1,0],[2,3]],[0,1]):
...     print(val)
(1, 0)
(0, 1)
(2, 0)
(3, 1) 
```  ## 特殊屬性和方法

另請參見

ndarray 的子類化

NumPy 提供了幾個類可以自定義的掛鉤:

```py
class.__array_ufunc__(ufunc, method, *inputs, **kwargs)

版本 1.13 中的新內容。

任何類,無論是 ndarray 的子類還是其他類,都可以定義此方法或將其設定為 None,以覆蓋 NumPy 的 ufunc 行為。這與 Python 的__mul__和其他二進位制操作例程非常相似。

  • ufunc 是被呼叫的 ufunc 物件。

  • method 是一個字串,指示呼叫哪個 Ufunc 方法(其中之一是"__call__""reduce""reduceat""accumulate""outer""inner")。

  • inputs 是傳遞給ufunc的輸入引數的元組。

  • kwargs 是一個包含 ufunc 的可選輸入引數的字典。如果給定,任何out引數,無論是位置引數還是關鍵字引數,都作為tuple傳遞給 kwargs。有關詳細資訊,請參見 Universal functions (ufunc) 中的討論。

該方法應返回操作的結果或者如果所請求的操作未實現,則返回NotImplemented

如果輸入、輸出或where引數中的一個具有__array_ufunc__方法,則會執行ufunc 而不是。 如果多個引數都實現了__array_ufunc__,則按順序嘗試:子類在超類之前,輸入在輸出之前,在where之前,否則從左到右。 第一個返回值不是NotImplemented的例程確定結果。 如果所有的__array_ufunc__操作都返回NotImplemented,則會引發TypeError

注意

我們打算將 numpy 函式重新實現為(廣義的)Ufunc,這樣它們就可以被__array_ufunc__方法覆蓋。 一個主要的候選物件是matmul,它目前不是一個 Ufunc,但可以相對容易地重寫為(一組)廣義的 Ufuncs。 同樣的情況可能會發生在函式如medianaminargsort

與 Python 中的其他一些特殊方法(如__hash____iter__)一樣,可以透過設定__array_ufunc__ = None來指示您的類支援 ufuncs。 當在設定了__array_ufunc__ = None的物件上呼叫 ufuncs 時,ufuncs 始終會引發TypeError

__array_ufunc__的存在也影響了ndarray如何處理二進位制操作,例如arr + objarr < 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__方法來實現。(注意,這意味著編寫一個始終返回NotImplemented__array_ufunc__並不完全等同於設定__array_ufunc__ = None:在前一種情況下,arr + obj會引發TypeError,而在後一種情況下,可以定義一個__radd__方法來防止這種情況發生。)

以上內容不適用於就地運算子,對於這些運算子,ndarray永遠不會返回NotImplemented。因此,arr += obj將總是導致TypeError。這是因為對於陣列來說,就地操作通常無法簡單地被一個簡單的反向操作所取代。(例如,預設情況下,arr += obj將被翻譯為arr = arr + obj,即arr將被替換,這與期望的就地陣列操作相反。)

注意

如果你定義了__array_ufunc__

  • 如果你不是ndarray的子類,我們建議你的類定義像__add____lt__這樣的特殊方法,它們像ndarray一樣委託給 ufunc。一個簡單的方法是從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____array_priority__機制(最終可能已被棄用)。

class.__array_function__(func, types, args, kwargs)

自版本 1.16 開始的新功能。

  • func是 NumPy 公共 API 中公開的任意可呼叫物件,以func(*args, **kwargs)的形式呼叫。

  • types是原始 NumPy 函式呼叫中實現__array_function__的唯一引數型別的集合collections.abc.Collection

  • 元組args和字典kwargs直接從原始呼叫中傳遞。

為了方便__array_function__的實現者,types提供了所有具有'__array_function__'屬性的引數型別。這使得實現者能夠快速識別應該推遲到其他引數的__array_function__實現的情況。實現不應依賴於types的迭代順序。

大多數__array_function__的實現將從以下兩個檢查開始:

  1. 給定的函式是我們知道如何過載的嗎?

  2. 所有引數都是我們知道如何處理的型別嗎?

如果這些條件成立,__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_FUNCTIONSfunc

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引數)。只有在 NumPy 函式呼叫中明確使用了可選引數時,才會將可選引數傳遞給__array_function__

就像內建特殊方法__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__方法,如下所示,但如果除了 NumPy 陣列子類之外的任何引數實現了__array_function__,它總是返回NotImplemented。)

__array_ufunc__當前行為的一個偏差是,NumPy 僅在每種唯一型別的第一個引數上呼叫__array_function__。這與 Python 的呼叫反射方法的規則相匹配,並確保即使有大量過載引數時,檢查過載也具有可接受的效能。

class.__array_finalize__(obj)

當系統從objobjndarray的子類(子型別))內部分配新陣列時會呼叫此方法。它可以用來在構造之後更改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__返回的物件。這種做法會引發TypeError

矩陣物件

注意

強烈建議不要使用矩陣子類。正如下文所述,這讓編寫可以始終處理矩陣和常規陣列的函式非常困難。目前,它們主要用於與 scipy.sparse 互動。但是我們希望提供另一種用途,最終移除 matrix 子類。

matrix 物件繼承自 ndarray ,因此它們具有與 ndarrays 相同的屬性和方法。然而,矩陣物件有六個重要的差異,可能導致在使用矩陣時出現意外結果但期望它們的行為類似於陣列的情況:

  1. 可以使用字串表示法建立矩陣物件,以允許 Matlab 風格的語法,其中空格分隔列,分號(‘;’)分隔行。

  2. 矩陣物件始終是二維的。這具有深遠影響,因為 m.ravel() 仍然是二維的(第一維度為 1),專案選擇返回二維物件,因此序列行為與陣列根本不同。

  3. 矩陣物件過載乘法以實現矩陣乘法。確保你理解了這一點,因為你可能需要接收矩陣的函式。特別是因為當 m 是矩陣時,asanyarray(m)返回一個矩陣。

  4. 矩陣物件過載冪運算以得到矩陣的冪。在使用 asanyarray(…) 獲取陣列物件的函式內部使用冪時,需要注意相同的警告。

  5. 矩陣物件的預設 array_priority 為 10.0,因此與 ndarray 的混合操作始終產生矩陣。

  6. 矩陣具有使計算更容易的特殊屬性。這些是

    matrix.T 返回矩陣的轉置。
    matrix.H 返回 self 的(複數)共軛轉置。
    matrix.I 返回可逆 self 的(乘法)逆。
    matrix.A self 返回為一個 ndarray 物件。

警告

矩陣物件過載乘法,‘*’,和冪,‘**’,分別用於矩陣乘法和矩陣冪。如果你的子程式能夠接受子類,並且你沒有轉換為基類陣列,則必須使用 ufuncs multiply 和 power 來確保對所有輸入執行正確的操作。

矩陣類是 ndarray 的 Python 子類,並可用作如何構造你自己的 ndarray 子類的參考。可以從其他矩陣、字串和任何可轉換為 ndarray 的內容建立矩陣。在 NumPy 中,名稱“mat”是“matrix”的別名。

matrix(data[, dtype, copy])

注意

不再建議使用這個類,即使是線性的

|

asmatrix(data[, dtype]) 將輸入解釋為矩陣。
bmat(obj[, ldict, gdict]) 從字串、巢狀序列或陣列構建一個矩陣物件。

示例 1:從字串建立矩陣

>>> a = np.mat('1 2 3; 4 5 3')
>>> print((a*a.T).I)
 [[ 0.29239766 -0.13450292]
 [-0.13450292  0.08187135]] 

示例 2:從巢狀序列建立矩陣

>>> np.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:從陣列建立矩陣

>>> np.mat(np.random.rand(3,3)).T
matrix([[4.17022005e-01, 3.02332573e-01, 1.86260211e-01],
 [7.20324493e-01, 1.46755891e-01, 3.45560727e-01],
 [1.14374817e-04, 9.23385948e-02, 3.96767474e-01]]) 

記憶體對映檔案陣列

記憶體對映檔案對於讀取和/或修改大檔案的正常佈局中的小段非常有用,而不需要將整個檔案讀入記憶體。一個簡單的 ndarray 的子類使用記憶體對映檔案作為陣列的資料緩衝區。對於小檔案,將整個檔案讀入記憶體的開銷通常不重要,但是對於大檔案,使用記憶體對映可以節省大量資源。

記憶體對映檔案陣列還有一個額外的方法(除了它們從 ndarray 繼承的方法):.flush() ,使用者必須手動呼叫它以確保對陣列的任何更改實際上被寫入到磁碟。

memmap(filename[, dtype, mode, offset, ...]) 在磁碟上的二進位制檔案中建立一個記憶體對映的陣列。
memmap.flush() 將陣列中的任何更改寫入到磁碟檔案中。

示例:

>>> a = np.memmap('newfile.dat', dtype=float, mode='w+', shape=1000)
>>> a[10] = 10.0
>>> a[30] = 30.0
>>> del a
>>> b = np.fromfile('newfile.dat', dtype=float)
>>> print(b[10], b[30])
10.0 30.0
>>> a = np.memmap('newfile.dat', dtype=float)
>>> print(a[10], a[30])
10.0 30.0 

字元陣列(numpy.char

另請參閱

建立字元陣列(numpy.char)

注意

chararray 類是為了向後相容 Numarray 而存在的,不建議用於新開發。從 numpy 1.4 開始,如果需要字串陣列,建議使用dtypeobject_bytes_str_ 陣列,並使用numpy.char 模組中的自由函式進行快速向量化的字串操作。

這些是增強型的陣列,型別為str_bytes_。 這些陣列繼承自ndarray,但特別定義了+*%操作,以(廣播)逐元素方式執行。 這些操作在標準的字元型別ndarray上不可用。 此外,chararray具有所有標準的str(和bytes)方法,並在逐元素的基礎上執行它們。 建立chararray最簡單的方法可能是使用self.view(chararray),其中self是一個 str 或 unicode 資料型別的 ndarray。 但是,也可以使用numpy.chararray建構函式或透過numpy.char.array函式來建立 chararray:

chararray(shape[, itemsize, unicode, ...]) 提供方便檢視字串和 Unicode 值陣列的檢視。
core.defchararray.array(obj[, itemsize, ...]) 建立一個chararray

與標準的 str 資料型別的 ndarray 的另一個區別是,chararray 繼承了由 Numarray 引入的特性,即陣列中任何元素末尾的空白將在項檢索和比較操作中被忽略。

記錄陣列 (numpy.rec)

參見

建立記錄陣列 (numpy.rec),資料型別例程,資料型別物件 (dtype)。

NumPy 提供了recarray類,允許將結構化陣列的欄位作為屬性進行訪問,並提供相應的標量資料型別物件record

recarray(shape[, dtype, buf, offset, ...]) 構造一個允許使用屬性進行欄位訪問的 ndarray。
record 允許欄位訪問作為屬性查詢的資料型別標量。

掩碼陣列(numpy.ma)

另請參閱

掩碼陣列

標準容器類

為了向後相容和作為標準的“容器”類,從 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 = next(myiter),直到迭代器引發 StopIteration。有幾種可能有用的陣列迭代方式:預設迭代、平坦迭代和 (N)-維列舉。

預設迭代

ndarray 物件的預設迭代器是序列型別的預設 Python 迭代器。因此,當陣列物件本身被用作迭代器時。預設行為等同於:

for i in range(arr.shape[0]):
    val = arr[i] 

這個預設迭代器從陣列中選擇一個 (N-1) 維的子陣列。這對於定義遞迴演算法可能是一個有用的構造。要迴圈整個陣列需要 (N) 個 for 迴圈。

>>> a = np.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 

在這裡,我使用了內建的 enumerate 迭代器來返回迭代器索引以及值。

N 維列舉

ndenumerate(arr) 多維索引迭代器。

有時在迭代時獲取 N 維索引可能很有用。ndenumerate 迭代器可以實現這個功能。

>>> for i, val in np.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 np.broadcast([[1,0],[2,3]],[0,1]):
...     print(val)
(1, 0)
(0, 1)
(2, 0)
(3, 1) 

預設迭代

ndarray 物件的預設迭代器是序列型別的預設 Python 迭代器。因此,當陣列物件本身被用作迭代器時,其預設行為等同於:

for i in range(arr.shape[0]):
    val = arr[i] 

此預設迭代器從陣列中選擇一個維度為 (N-1) 的子陣列。這對於定義遞迴演算法可能是一個有用的構造。要遍歷整個陣列需要 (N) 個 for 迴圈。

>>> a = np.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 

在這裡,我已經使用了內建的 enumerate 迭代器來返回迭代器索引以及值。

N 維列舉

ndenumerate(arr) 多維索引迭代器。

有時,在迭代時獲取 N 維索引可能很有用。ndenumerate 迭代器可以實現這一點。

>>> for i, val in np.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 np.broadcast([[1,0],[2,3]],[0,1]):
...     print(val)
(1, 0)
(0, 1)
(2, 0)
(3, 1) 

numpy.matrix.T

numpy.org/doc/1.26/reference/generated/numpy.matrix.T.html

屬性

property matrix.T

返回矩陣的轉置。

進行共軛!對於複共軛轉置,請使用.H

引數:

返回:

ret矩陣物件

(非共軛)矩陣的轉置。

另請參閱

transpose, getH

示例

>>> m = np.matrix('[1, 2; 3, 4]')
>>> m
matrix([[1, 2],
 [3, 4]])
>>> m.getT()
matrix([[1, 3],
 [2, 4]]) 

numpy.matrix.H

原文:numpy.org/doc/1.26/reference/generated/numpy.matrix.H.html

屬性

property matrix.H

返回self的(復)共軛轉置。

如果self是實數值,相當於np.transpose(self)

引數:

None

返回:

ret矩陣物件

self的複共軛轉置

示例

>>> x = np.matrix(np.arange(12).reshape((3,4)))
>>> z = x - 1j*x; z
matrix([[  0\. +0.j,   1\. -1.j,   2\. -2.j,   3\. -3.j],
 [  4\. -4.j,   5\. -5.j,   6\. -6.j,   7\. -7.j],
 [  8\. -8.j,   9\. -9.j,  10.-10.j,  11.-11.j]])
>>> z.getH()
matrix([[ 0\. -0.j,  4\. +4.j,  8\. +8.j],
 [ 1\. +1.j,  5\. +5.j,  9\. +9.j],
 [ 2\. +2.j,  6\. +6.j, 10.+10.j],
 [ 3\. +3.j,  7\. +7.j, 11.+11.j]]) 

numpy.matrix.I

原文:numpy.org/doc/1.26/reference/generated/numpy.matrix.I.html

屬性

property matrix.I

返回可逆self的(乘法)逆。

引數:

None

返回:

ret矩陣物件

如果self是非奇異的,則ret滿足ret * self == self * ret == np.matrix(np.eye(self[0,:].size)) 的條件都返回True

引發:

numpy.linalg.LinAlgError: 奇異矩陣

如果self是奇異的。

參見

linalg.inv

示例

>>> m = np.matrix('[1, 2; 3, 4]'); m
matrix([[1, 2],
 [3, 4]])
>>> m.getI()
matrix([[-2\. ,  1\. ],
 [ 1.5, -0.5]])
>>> m.getI() * m
matrix([[ 1.,  0.], # may vary
 [ 0.,  1.]]) 

numpy.matrix.A

原文:numpy.org/doc/1.26/reference/generated/numpy.matrix.A.html

屬性

property matrix.A

ndarray物件的形式返回自身

等同於np.asarray(self)

引數:

返回值:

retndarray

自身作為ndarray物件

示例

>>> x = np.matrix(np.arange(12).reshape((3,4))); x
matrix([[ 0,  1,  2,  3],
 [ 4,  5,  6,  7],
 [ 8,  9, 10, 11]])
>>> x.getA()
array([[ 0,  1,  2,  3],
 [ 4,  5,  6,  7],
 [ 8,  9, 10, 11]]) 

numpy.matrix

原文:numpy.org/doc/1.26/reference/generated/numpy.matrix.html

class numpy.matrix(data, dtype=None, copy=True)

注意

不再建議使用這個類,甚至對於線性代數也不建議。請使用正規的陣列。該類可能會在未來被移除。

從一個類似陣列的物件或資料字串返回一個矩陣。矩陣是一個專門化的保持其二維性質的二維陣列。它有一些特殊的運算子,比如*(矩陣乘法)和**(矩陣冪)。

引數:

dataarray_like or string

如果data是一個字串,它會被解釋為以逗號或空格分隔列,用分號分隔行的矩陣。

dtype資料型別

輸出矩陣的資料型別。

copybool

如果data已經是一個ndarray,則此標誌確定資料是被複制(預設)還是被構建為檢視。

另請參閱

array

示例

>>> a = np.matrix('1 2; 3 4')
>>> a
matrix([[1, 2],
 [3, 4]]) 
>>> np.matrix([[1, 2], [3, 4]])
matrix([[1, 2],
 [3, 4]]) 

屬性:

A

作為一個ndarray物件返回 self

A1

self 作為一個扁平化的ndarray返回。

H

返回 self 的(複數)共軛轉置。

I

返回 self 可逆的(乘法)逆。

T

返回矩陣的轉置。

base

如果記憶體來自其他物件,則為基礎物件。

ctypes

一個簡化陣列與 ctypes 模組互動的物件。

data

指向陣列資料起始位置的 Python 緩衝物件。

dtype

陣列元素的資料型別。

flags

陣列的記憶體佈局資訊。

flat

陣列的一維迭代器。

imag

陣列的虛部。

itemsize

一個陣列元素的位元組長度。

nbytes

陣列元素消耗的總位元組數。

ndim

陣列維度數量。

real

陣列的實部。

shape

陣列維度的元組。

size

陣列中的元素數量。

strides

遍歷陣列時,在每個維度上的步長的位元組元組。

方法

all([axis, out]) 測試沿給定軸的所有矩陣元素是否評估為 True。
any([axis, out]) 測試沿給定軸的任何陣列元素是否評估為 True。
argmax([axis, out]) 沿軸的最大值的索引。
argmin([axis, out]) 沿軸的最小值的索引。
argpartition(kth[, axis, kind, order]) 返回將此陣列分割槽的索引。
argsort([axis, kind, order]) 返回將此陣列排序的索引。
astype(dtype[, order, casting, subok, copy]) 複製為指定型別的陣列。
byteswap([inplace]) 交換陣列元素的位元組。
choose(choices[, out, mode]) 使用索引陣列從一組選擇中構造新陣列。
clip([min, max, out]) 返回其值限制為[min, max]的陣列。
compress(condition[, axis, out]) 沿給定軸返回此陣列的選定切片。
conj() 複共軛所有元素。
conjugate() 返回元素的複共軛。
copy([order]) 返回陣列的副本。
cumprod([axis, dtype, out]) 返回沿給定軸的元素的累積乘積。
cumsum([axis, dtype, out]) 返回沿給定軸的元素的累積和。
diagonal([offset, axis1, axis2]) 返回指定對角線。
dump(file) 將陣列的 pickle 轉儲到指定的檔案中。
dumps() 將陣列的 pickle 作為字串返回。
fill(value) 用標量值填充陣列。
flatten([order]) 返回矩陣的平展副本。
getA() ndarray 物件的形式返回 self
getA1() self 作為一個平展的 ndarray 返回。
getH() 返回 self 的(複數)共軛轉置。
getI() 返回可逆 self 的(乘法)逆。
getT() 返回矩陣的轉置。
getfield(dtype[, offset]) 將給定陣列的欄位按特定型別返回。
item(*args) 將陣列的一個元素複製到標準 Python 標量並返回。
itemset(*args) 將標量插入陣列(如果可能,將標量強制轉換為陣列的 dtype)。
max([axis, out]) 返回沿某個軸的最大值。
mean([axis, dtype, out]) 返回沿給定軸的矩陣元素的平均值。
min([axis, out]) 返回沿某個軸的最小值。
newbyteorder([new_order]) 返回以不同位元組順序檢視的相同資料的陣列。
nonzero() 返回非零元素的索引。
partition(kth[, axis, kind, order]) 重新排列陣列中的元素,使第 k 個位置的元素的值處於排序後陣列中的位置。
prod([axis, dtype, out]) 返回沿給定軸的陣列元素的乘積。
ptp([axis, out]) 沿給定軸的峰值到谷值(最大值 - 最小值)。
put(indices, values[, mode]) 對所有 n 在索引中的值,設定 a.flat[n] = values[n]
ravel([order]) 返回一個扁平化的矩陣。
repeat(repeats[, axis]) 重複陣列的元素。
reshape(shape[, order]) 返回包含相同資料的新形狀的陣列。
resize(new_shape[, refcheck]) 就地更改陣列的形狀和大小。
round([decimals, out]) 返回每個元素四捨五入到給定小數位的 a
searchsorted(v[, side, sorter]) 查詢應插入陣列 a 中元素v 的索引,以保持順序。
setfield(val, dtype[, offset]) 將一個值放入由資料型別定義的欄位中的指定位置。
setflags([write, align, uic]) 分別設定陣列標誌 WRITEABLE、ALIGNED、WRITEBACKIFCOPY。
sort([axis, kind, order]) 就地��陣列進行排序。
squeeze([axis]) 返回一個可能重新塑形的矩陣。
std([axis, dtype, out, ddof]) 返回沿給定軸的陣列元素的標準偏差。
sum([axis, dtype, out]) 返回矩陣元素沿給定軸的和。
swapaxes(axis1, axis2) 返回陣列的檢視,axis1axis2 互換。
take(indices[, axis, out, mode]) 返回陣列 a 中給定索引處的元素組成的陣列。
tobytes([order]) 構建包含陣列中原始資料位元組的 Python 位元組。
tofile(fid[, sep, format]) 將陣列以文字或二進位制(預設)形式寫入檔案。
tolist() 將矩陣返回為一個(可能巢狀的)列表。
tostring([order]) tobytes完全相同的行為的相容別名。
trace([offset, axis1, axis2, dtype, out]) 返回陣列對角線上的和。
transpose(*axes) 返回陣列的軸被轉置後的檢視。
var([axis, dtype, out, ddof]) 返回矩陣元素沿給定軸的方差。
view([dtype][, type]) 具有相同資料的陣列的新檢視。
dot

numpy.asmatrix

原文:numpy.org/doc/1.26/reference/generated/numpy.asmatrix.html

numpy.asmatrix(data, dtype=None)

將輸入解釋為矩陣。

不像matrix,如果輸入已經是矩陣或 ndarray,asmatrix不會建立副本。等同於matrix(data, copy=False)

引數:

data類似陣列

輸入資料。

dtype資料型別

輸出矩陣的資料型別。

返回:

mat矩陣

data 解釋為矩陣。

示例

>>> x = np.array([[1, 2], [3, 4]]) 
>>> m = np.asmatrix(x) 
>>> x[0,0] = 5 
>>> m
matrix([[5, 2],
 [3, 4]]) 

numpy.bmat

原文:numpy.org/doc/1.26/reference/generated/numpy.bmat.html

numpy.bmat(obj, ldict=None, gdict=None)

從字串、巢狀序列或陣列構建一個矩陣物件。

引數:

obj字串或類陣列

輸入資料。如果是字串,則可以透過名稱引用當前範圍內的變數。

ldict字典,可選

一個字典,用於替換當前幀中的區域性運算元。如果obj不是字串或gdict為 None,則忽略。

gdict字典,可選

一個字典,用於替換當前幀中的全域性運算元。如果obj不是字串,則忽略。

返回值:

out矩陣

返回一個矩陣物件,這是一個專門的二維陣列。

另請參閱

block

對於 N 維陣列的此函式的一般化,返回普通的 ndarray。

示例

>>> A = np.mat('1 1; 1 1')
>>> B = np.mat('2 2; 2 2')
>>> C = np.mat('3 4; 5 6')
>>> D = np.mat('7 8; 9 0') 

以下所有表示式構造相同的塊矩陣:

>>> np.bmat([[A, B], [C, D]])
matrix([[1, 1, 2, 2],
 [1, 1, 2, 2],
 [3, 4, 7, 8],
 [5, 6, 9, 0]])
>>> np.bmat(np.r_[np.c_[A, B], np.c_[C, D]])
matrix([[1, 1, 2, 2],
 [1, 1, 2, 2],
 [3, 4, 7, 8],
 [5, 6, 9, 0]])
>>> np.bmat('A,B; C,D')
matrix([[1, 1, 2, 2],
 [1, 1, 2, 2],
 [3, 4, 7, 8],
 [5, 6, 9, 0]]) 

numpy.memmap

原文:numpy.org/doc/1.26/reference/generated/numpy.memmap.html

class numpy.memmap(filename, dtype=<class 'numpy.ubyte'>, mode='r+', offset=0, shape=None, order='C')

在磁碟上的二進位制檔案中建立一個陣列的記憶體對映。

記憶體對映檔案被用於訪問磁碟上大檔案的小片段,而不需要將整個檔案讀入記憶體。NumPy 的memmap是類似陣列的物件。這與 Python 的mmap模組不同,後者使用類似檔案的物件。

由於這個 ndarray 的子類與一些操作有一些不愉快的互動,因為它不太適合作為一個子類。使用這個子類的另一種方法是自己建立mmap物件,然後直接用ndarray.__new__建立一個 ndarray,將建立的物件傳遞給它的‘buffer=’引數。

這個類在一定時候可能會被轉換成一個工廠函式,返回一個檢視到一個mmap緩衝區。

重新整理memmap例項以將更改寫入檔案。目前沒有 API 來關閉底層的mmap。確保資源實際上關閉是有技巧的,因為它可能在不同的memmap例項之間共享。

引數:

檔名字串,類似檔案物件或 pathlib.Path 例項

用作陣列資料緩衝區的檔名或檔案物件。

dtype資料型別,可選

用於解釋檔案內容的資料型別。預設為uint8

模式,可選

以這種模式開啟檔案:

‘r’ 僅開啟現有檔案以供讀取。
‘r+’ 開啟現有檔案以供讀取和寫入。
‘w+’ 建立或覆蓋現有檔案以供讀取和寫入。如果mode == 'w+',則必須同時指定shape
‘c’ 寫時複製:賦值影響記憶體中的資料,但更改不會儲存到磁碟上。檔案是隻讀的。

預設為‘r+’。

偏移量整數,可選

在檔案中,陣列資料從這個偏移量開始。由於offset以位元組為單位,所以通常應該是dtype的位元組大小的倍數。當mode != 'r'時,甚至檔案末尾之後的正偏移量也是有效的;檔案將被擴充套件以容納附加資料。預設情況下,memmap將從檔案的開頭開始,即使filename是檔案指標fpfp.tell() != 0

形狀元組,可選

陣列的期望形狀。如果mode == 'r'並且offset之後剩餘的位元組數不是dtype的位元組大小的倍數,你必須指定shape。預設情況下,返回的陣列將是 1-D 陣列,其元素數量由檔案大小和資料型別確定。

順序,可選

指定 ndarray 記憶體佈局的順序:行優先、C 風格或列優先、Fortran 風格。只有在形狀大於 1-D 時才會生效。預設順序是 ‘C’。

另請參閱

lib.format.open_memmap

建立或載入一個記憶體對映的.npy檔案。

注意事項

memmap 物件可用於任何接受 ndarray 的地方。給定一個 memmap fpisinstance(fp, numpy.ndarray) 返回 True

記憶體對映檔案在 32 位系統上不能超過 2GB。

當 memmap 導致在檔案系統中建立或擴充套件超出當前大小的檔案時,新部分的內容是未指定的。在具有 POSIX 檔案系統語義的系統上,擴充套件部分將填充為零位元組。

示例

>>> data = np.arange(12, dtype='float32')
>>> data.resize((3,4)) 

此示例使用一個臨時檔案,以便 doctest 不會將檔案寫入您的目錄。您會使用一個‘正常’的檔名。

>>> from tempfile import mkdtemp
>>> import os.path as path
>>> filename = path.join(mkdtemp(), 'newfile.dat') 

建立一個與我們的資料匹配的 dtype 和形狀的 memmap:

>>> fp = np.memmap(filename, dtype='float32', mode='w+', shape=(3,4))
>>> fp
memmap([[0., 0., 0., 0.],
 [0., 0., 0., 0.],
 [0., 0., 0., 0.]], dtype=float32) 

將資料寫入 memmap 陣列:

>>> fp[:] = data[:]
>>> fp
memmap([[  0.,   1.,   2.,   3.],
 [  4.,   5.,   6.,   7.],
 [  8.,   9.,  10.,  11.]], dtype=float32) 
>>> fp.filename == path.abspath(filename)
True 

重新整理記憶體更改以便讀取它們

>>> fp.flush() 

載入 memmap 並驗證資料已儲存:

>>> newfp = np.memmap(filename, dtype='float32', mode='r', shape=(3,4))
>>> newfp
memmap([[  0.,   1.,   2.,   3.],
 [  4.,   5.,   6.,   7.],
 [  8.,   9.,  10.,  11.]], dtype=float32) 

只讀 memmap:

>>> fpr = np.memmap(filename, dtype='float32', mode='r', shape=(3,4))
>>> fpr.flags.writeable
False 

寫時複製 memmap:

>>> fpc = np.memmap(filename, dtype='float32', mode='c', shape=(3,4))
>>> fpc.flags.writeable
True 

可以將值分配給寫時複製陣列,但值僅寫入陣列的記憶體副本,而不寫入磁碟:

>>> fpc
memmap([[  0.,   1.,   2.,   3.],
 [  4.,   5.,   6.,   7.],
 [  8.,   9.,  10.,  11.]], dtype=float32)
>>> fpc[0,:] = 0
>>> fpc
memmap([[  0.,   0.,   0.,   0.],
 [  4.,   5.,   6.,   7.],
 [  8.,   9.,  10.,  11.]], dtype=float32) 

磁碟上的檔案保持不變:

>>> fpr
memmap([[  0.,   1.,   2.,   3.],
 [  4.,   5.,   6.,   7.],
 [  8.,   9.,  10.,  11.]], dtype=float32) 

memmap 的偏移:

>>> fpo = np.memmap(filename, dtype='float32', mode='r', offset=16)
>>> fpo
memmap([  4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.], dtype=float32) 

屬性:

檔名str 或 pathlib.Path 例項

對映檔案的路徑。

偏移量int

檔案中的偏移位置。

模式str

檔案模式。

方法

flush() 將陣列中的任何更改寫入磁碟上的檔案。

numpy.memmap.flush

原文:numpy.org/doc/1.26/reference/generated/numpy.memmap.flush.html

方法

memmap.flush()

將陣列中的任何更改寫入磁碟上的檔案。

如需更多資訊,請參閱memmap

引數:

另請參閱

memmap

numpy.chararray

numpy.org/doc/1.26/reference/generated/numpy.chararray.html

class numpy.chararray(shape, itemsize=1, unicode=False, buffer=None, offset=0, strides=None, order=None)

為字串和 unicode 值的陣列提供了便利的檢視。

注意

chararray類是為了向後相容 Numarray 而存在的,不建議用於新開發。從 numpy 1.4 開始,如果需要字串陣列,則建議使用dtypeobject_bytes_str_的陣列,並使用numpy.char模組中的自由函式執行快速向量化字串操作。

與普通的型別為strunicode的 NumPy 陣列相比,此類新增了以下功能:

  1. 索引時,對值自動從末尾去除空格
  2. 比較運算子在比較值時會自動從末尾去除空格。
  3. 提供向量化字串操作作為方法(例如endswith)和中綴運算子(例如+*%

應該使用numpy.char.arraynumpy.char.asarray來建立 chararrays,而不是直接使用該建構函式。

此建構函式建立陣列,使用buffer(帶有offsetstrides)如果不為None的話。如果bufferNone,則構造一個C 順序的新陣列,除非len(shape) >= 2order='F',在這種情況下,stridesFortran 順序

引數:

shape元組

陣列的形狀。

itemsizeint,可選

每個陣列元素的長度,以字元數表示。預設為 1。

unicodebool,可選

陣列元素是 unicode(True)還是 string(False)。預設為 False。

buffer暴露緩衝介面的物件或 str,可選

陣列資料的起始記憶體地址。預設為 None,此時將建立一個新陣列。

offsetint,可選

從軸的起始處的固定步長位移?預設為 0。必須是>=0。

stridesint 的陣列樣式,可選

陣列的步幅(完整說明請參見ndarray.strides)。預設為 None。

order,可選

陣列資料在記憶體中儲存的順序:‘C’ -> “行優先”順序(預設),‘F’ -> “列優先”(Fortran)順序。

示例

>>> charar = np.chararray((3, 3))
>>> charar[:] = 'a'
>>> charar
chararray([[b'a', b'a', b'a'],
 [b'a', b'a', b'a'],
 [b'a', b'a', b'a']], dtype='|S1') 
>>> charar = np.chararray(charar.shape, itemsize=5)
>>> charar[:] = 'abc'
>>> charar
chararray([[b'abc', b'abc', b'abc'],
 [b'abc', b'abc', b'abc'],
 [b'abc', b'abc', b'abc']], dtype='|S5') 

屬性:

T

轉置陣列的檢視。

base

如果儲存在記憶體中的陣列來自其他物件,則為基礎物件。

ctypes

一個用來簡化陣列與 ctypes 模組互動的物件。

data

指向陣列資料起始位置的 Python 緩衝區物件。

dtype

陣列元素的資料型別。

flags

有關陣列記憶體佈局的資訊。

flat

陣列的 1-D 迭代器。

imag

陣列的虛部。

itemsize

每個陣列元素的位元組數。

nbytes

陣列元素消耗的總位元組數。

ndim

陣列的維度數量。

real

陣列的實部。

shape

陣列的維度的元組。

size

陣列中的元素數量。

strides

每個維度在遍歷陣列時的步長的元組。

方法

astype(資料型別[, 順序, 強制轉換, 可替代, 複製]) 陣列的副本,轉換為指定型別。
argsort([軸, 種類, 順序]) 返回對陣列排序後的索引。
copy([順序]) 返回陣列的副本。
count(子串[, 起始, 結束]) 返回陣列中子串 sub 在區間 [start, end] 內非重疊出現的次數的陣列。
decode([編碼, 錯誤]) 逐元素呼叫 bytes.decode
dump(檔案) 將陣列的 pickle 轉儲到指定檔案。
dumps() 返回陣列的 pickle 格式字串。
encode([encoding, errors]) 逐元素呼叫 str.encode
endswith(suffix[, start, end]) 返回布林陣列,在其中 self 中的字串元素以 suffix 結尾則為 True,否則為 False
expandtabs([tabsize]) 返回將每個字串元素中的所有制表符替換為一個或多個空格的副本。
fill(value) 用標量值填充陣列。
find(sub[, start, end]) 對於每個元素,返回字串中發現子字串 sub 的最低索引。
flatten([order]) 返回壓縮為一維的陣列副本。
getfield(dtype[, offset]) 將給定陣列的欄位作為特定型別返回。
index(sub[, start, end]) 類似於 find,但在子字串未找到時會引發 ValueError
isalnum() 如果字串中的所有字元均為字母數字字元且至少有一個字元,則對每個元素返回 true,否則返回 false。
isalpha() 如果字串中的所有字元均為字母字元且至少有一個字元,則對每個元素返回 true,否則返回 false。
isdecimal() 對於 self 中的每個元素,如果元素中只有十進位制字元,則返回 True。
isdigit() 如果字串中的所有字元均為數字字元且至少有一個字元,則對每個元素返回 true,否則返回 false。
islower() 如果字串中的所有大小寫字元均為小寫字母且至少有一個大小寫字元,則對每個元素返回 true,否則返回 false。
isnumeric() 對於 self 中的每個元素,如果元素中只有數值字元,則返回 True。
isspace() 對於每個元素,如果字串中只包含空白字元並且至少有一個字元,則返回 true;否則返回 false。
istitle() 對於每個元素,如果該元素是一個標題化的字串並且至少有一個字元,則返回 true;否則返回 false。
isupper() 對於每個元素,如果字串中的所有字母都是大寫字母並且至少有一個字元,則返回 true;否則返回 false。
item(*args) 將陣列的一個元素複製到一個標準的 Python 標量並返回它。
join(seq) 返回一個由序列 seq 中的字串連線而成的字串。
ljust(width[, fillchar]) 返回一個將 self 中的元素左對齊到長度為 width 的字串中的陣列。
lower() 返回一個將 self 中的元素轉換為小寫的陣列。
lstrip([chars]) 對於 self 中的每個元素,返回一個刪除前導字元的副本。
nonzero() 返回非零元素的索引。
put(indices, values[, mode]) 對於所有 n 在索引中的元素,設定 a.flat[n] = values[n]
ravel([order]) 返回一個扁平化的陣列。
repeat(repeats[, axis]) 重複陣列的元素。
replace(old, new[, count]) 對於 self 中的每個元素,返回一個將所有子字串 old 的出現替換為 new 的字串副本。
reshape(shape[, order]) 返回一個包含相同資料但具有新形狀的陣列。
resize(new_shape[, refcheck]) 原地更改陣列的形狀和大小。
rfind(sub[, start, end]) 對於 self 中的每個元素,返回字串中子字串 sub 最高索引的位置,其中 sub 包含在 [start, end] 內。
rindex(sub[, start, end]) 類似於rfind,但在子字串sub未找到時引發ValueError
rjust(width[, fillchar]) 返回一個將self中的元素右對齊在長度為width的字串中的陣列。
rsplit([sep, maxsplit]) self中的每個元素,使用sep作為分隔符,返回字串中單詞的列表。
rstrip([chars]) self中的每個元素,返回一個副本,其中移除了尾隨字元。
searchsorted(v[, side, sorter]) 找到應該插入陣列 a 的位置索引,以保持順序。
setfield(val, dtype[, offset]) 在由資料型別定義的欄位的指定位置放置一個值。
setflags([write, align, uic]) 設定陣列標誌 WRITEABLE、ALIGNED、WRITEBACKIFCOPY。
sort([axis, kind, order]) 對陣列進行原地排序。
split([sep, maxsplit]) self中的每個元素,使用sep作為分隔符,返回字串中單詞的列表。
splitlines([keepends]) self中的每個元素,在換行符處中斷,返回元素中的行列表。
squeeze([axis]) a中刪除長度為一的軸。
startswith(prefix[, start, end]) 返回一個布林陣列,其中True表示self中的字串元素以prefix開頭,否則為False
strip([chars]) self中的每個元素,返回一個副本,其中移除了前導和尾隨字元。
swapaxes(axis1, axis2) 返回一個將axis1axis2交換的陣列檢視。
swapcase() 對於self中的每個元素,返回將大寫字元轉換為小寫字元,反之亦然的字串副本。
take(indices[, axis, out, mode]) 返回從給定索引處的a的元素形成的陣列。
title() 對於self中的每個元素,返回字串的.title()版本:單詞以大寫字元開頭,所有其餘大小寫字元為小寫。
tofile(fid[, sep, format]) 將陣列寫入檔案為文字或二進位制(預設)。
tolist() 將陣列作為 Python 標量的a.ndim級別深度巢狀列表返回。
tostring([order]) tobytes完全具有相同行為的相容別名。
translate(table[, deletechars]) 對於self中的每個元素,返回刪除了可選引數deletechars中出現的所有字元,並且剩餘字元已透過給定的轉換表對映的字串副本。
transpose(*axes) 返回具有轉置軸的陣列的檢視。
upper() 返回將self中的元素轉換為大寫的陣列。
view([dtype][, type]) 具有相同資料的陣列的新檢視。
zfill(width) 返回長度為width的字串中左側用零填充的數字字串。

numpy.core.defchararray.array

原文:numpy.org/doc/1.26/reference/generated/numpy.core.defchararray.array.html

core.defchararray.array(obj, itemsize=None, copy=True, unicode=None, order=None)

建立一個 chararray

注意

此類用於 numarray 的向後相容性。新程式碼(不關心 numarray 相容性)應使用型別為 bytes_str_ 的陣列,並使用 numpy.char 中的免費函式進行快速的向量化字串操作。

與型別為 strunicode 的常規 NumPy 陣列相比,此類新增了以下功能:

  1. 在索引值時,自動從末尾刪除空格
  2. 比較運算子在比較值時自動從末尾刪除空格
  3. 向量化的字串操作被提供為方法(例如 str.endswith)和中綴運算子(例如 +, *, %

引數:

obj字串陣列或類似 unicode 的物件

itemsize整數,可選

itemsize 是結果陣列中每個標量的字元數。如果 itemsize 為 None,並且 obj 是物件陣列或 Python 列表,則 itemsize 將自動確定。如果提供了 itemsize 並且 obj 的型別為 str 或 unicode,則 obj 字串將被分成 itemsize 個片段。

copy布林值,可選

如果為 true(預設值),則物件將被複制。否則,僅當 array 返回副本時,如果 obj 是巢狀序列,或者如果需要複製以滿足其他要求(itemsize、unicode、order 等),則會進行復制。

unicode布林值,可選

當為 true 時,結果的 chararray 可以包含 Unicode 字元;當為 false 時,僅包含 8 位字元。如果 unicode 為 None,並且 obj 是以下內容之一:

  • 一個 chararray,
  • 型別為 strunicode 的 ndarray
  • 一個 Python str 或 unicode 物件,

然後輸出陣列的 unicode 設定將自動確定。

order,可選

指定陣列的順序。如果順序為‘C’(預設值),則陣列將按 C 連續順序排列(最後一個索引變化最快)。如果順序為‘F’,則返回的陣列將按 Fortran 連續順序排列(第一個索引變化最快)。如果順序為‘A’,則返回的陣列可以按任何順序排列(C 連續、Fortran 連續甚至不連續)。

numpy.recarray

原文:numpy.org/doc/1.26/reference/generated/numpy.recarray.html

class numpy.recarray(shape, dtype=None, buf=None, offset=0, strides=None, formats=None, names=None, titles=None, byteorder=None, aligned=False, order='C')

構造一個允許使用屬性訪問欄位的 ndarray。

陣列可能包含包含欄位的資料型別,類似於電子表格中的列。一個示例是[(x, int), (y, float)],其中陣列中的每個條目都是一個(int, float)的對。通常,這些屬性透過字典查詢來訪問,例如arr['x']arr['y']。記錄陣列允許以陣列的成員方式訪問欄位,使用arr.xarr.y

引數:

shape元組

輸出陣列的形狀。

dtype資料型別,可選

所需資料型別。預設情況下,資料型別是根據formatsnamestitlesalignedbyteorder確定的。

formats資料型別列表,可選

包含不同列的資料型別的列表,例如['i4', 'f8', 'i4']formats不支援直接使用型別的新約定,即(int, float, int)。請注意,formats必須是列表,而不是元組。鑑於formats有些受限,我們建議優先指定dtype

names字串元組,可選

每列的名稱,例如('x', 'y', 'z')

buf緩衝區,可選

預設情況下,將建立一個給定形狀和資料型別的新陣列。如果指定了buf且是一個暴露緩衝區介面的物件,則陣列將使用現有緩衝區的記憶體。在這種情況下,offsetstrides關鍵字可用。

返回:

recrecarray

給定形狀和型別的空陣列。

其他引數:

titles字串元組,可選

列名稱的別名。例如,如果names('x', 'y', 'z')titles('x_coordinate', 'y_coordinate', 'z_coordinate'),那麼arr['x']等同於arr.xarr.x_coordinate

byteorder,可選

所有欄位的位元組順序。

aligned布林值,可選

將欄位在記憶體中對齊,就像 C 編譯器會做的那樣。

strides整數元組,可選

緩衝區(buf)根據這些步幅解釋(步幅定義了記憶體中每個陣列元素、行、列等佔用多少位元組)。

offset整數,可選

從此偏移開始讀取緩衝區(buf)。

order,可選

行主(C 樣式)或列主(Fortran 樣式)順序。

參見

core.records.fromrecords

從資料構造一個記錄陣列。

record

recarray的基本資料型別。

format_parser

從格式、名稱、標題確定資料型別。

注意

這個建構函式可以與empty進行比較:它建立一個新的記錄陣列,但不填充資料。要從資料建立記錄陣列,請使用以下方法之一:

  1. 建立一個標準的 ndarray 並將其轉換為記錄陣列,使用arr.view(np.recarray)

  2. 使用buf關鍵字。

  3. 使用np.rec.fromrecords

示例

建立一個具有兩個欄位xy的陣列:

>>> x = np.array([(1.0, 2), (3.0, 4)], dtype=[('x', '<f8'), ('y', '<i8')])
>>> x
array([(1., 2), (3., 4)], dtype=[('x', '<f8'), ('y', '<i8')]) 
>>> x['x']
array([1., 3.]) 

以記錄陣列的形式檢視陣列:

>>> x = x.view(np.recarray) 
>>> x.x
array([1., 3.]) 
>>> x.y
array([2, 4]) 

建立一個新的空記錄陣列:

>>> np.recarray((2,),
... dtype=[('x', int), ('y', float), ('z', int)]) 
rec.array([(-1073741821, 1.2249118382103472e-301, 24547520),
 (3471280, 1.2134086255804012e-316, 0)],
 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '<i4')]) 

屬性:

T

轉置陣列的檢視。

base

如果記憶體來自其他物件,則為基本物件。

ctypes

一個方便與 ctypes 模組互動的物件。

data

指向陣列資料起始位置的 Python 緩衝物件。

dtype

陣列元素的資料型別。

flags

陣列的記憶體佈局資訊。

flat

陣列的 1-D 迭代器。

imag

陣列的虛部。

itemsize

每個陣列元素的位元組長度。

nbytes

陣列元素消耗的總位元組數。

ndim

陣列的維度數。

real

陣列的實部。

shape

陣列維度的元組。

size

陣列中的元素個數。

strides

遍歷陣列時在每個維度上步進的位元組數元組。

方法

all([axis, out, keepdims, where]) 如果所有元素求值為 True,則返回 True。
any([axis, out, keepdims, where]) 如果a中的任何元素求值為 True,則返回 True。
argmax([axis, out, keepdims]) 返回沿給定軸的最大值的索引。
argmin([axis, out, keepdims]) 返回沿給定軸的最小值的索引。
argpartition 返回將此陣列劃分的索引。
argsort 返回按順序對此陣列進行排序的索引。
astype 陣列的副本,轉換為指定的型別。
byteswap 交換陣列元素的位元組。
choose 使用索引陣列從一組選擇中構建新陣列。
clip 返回其值限制為[min, max]的陣列。
compress 返回沿著給定軸選定的陣列切片。
conj 複共軛所有元素。
conjugate 返回複共軛,逐個元素。
copy 返回陣列的副本。
cumprod 返回沿給定軸的元素的累積乘積。
cumsum 返回沿給定軸的元素的累積總和。
diagonal 返回指定的對角線。
dump 將陣列的 pickle 轉儲到指定檔案。
dumps 將陣列的 pickle 作為字串返回。
fill 使用標量值填充陣列。
flatten 返回摺疊成一維的陣列的副本。
getfield 返回給定陣列的欄位作為某種型別。
item 將陣列的元素複製到標準 Python 標量並返回。
itemset(*args) 將標量插入陣列(如果可能,標量會被轉換為陣列的資料型別)。
max([axis, out, keepdims, initial, where]) 沿著給定軸返回最大值。
mean([axis, dtype, out, keepdims, where]) 返回沿給定軸的陣列元素的平均值。
min([axis, out, keepdims, initial, where]) 沿著給定軸返回最小值。
newbyteorder([new_order]) 返回使用不同位元組順序檢視的相同資料的陣列。
nonzero() 返回非零元素的索引。
partition(kth[, axis, kind, order]) 透過重新排列陣列中的元素,使得第 k 個位置的元素的值在排序陣列中的位置處於預期位置。
prod([axis, dtype, out, keepdims, initial, ...]) 返回沿給定軸的陣列元素的乘積。
ptp([axis, out, keepdims]) 沿著給定軸的峰值到峰值(最大值 - 最小值)。
put(indices, values[, mode]) 設定a.flat[n] = values[n],其中n為 indices 中的所有值。
ravel([order]) 返回一個扁平化的陣列。
repeat(repeats[, axis]) 重複陣列的元素。
reshape(shape[, order]) 返回一個包含與新形狀相同資料的陣列。
resize(new_shape[, refcheck]) 原地改變陣列的形狀和大小。
round([decimals, out]) 返回每個元素舍入到給定小數位數的a
searchsorted(v[, side, sorter]) 查詢應該在陣列 a 中插入 v 元素以保持順序的索引。
setfield(val, dtype[, offset]) 在由資料型別定義的欄位的指定位置放入一個值。
setflags([write, align, uic]) 分別設定陣列標誌 WRITEABLE、ALIGNED、WRITEBACKIFCOPY。
sort([axis, kind, order]) 原地對陣列進行排序。
squeeze([axis]) a 中刪除長度為一的軸。
std([axis, dtype, out, ddof, keepdims, where]) 返回給定軸上陣列元素的標準差。
sum([axis, dtype, out, keepdims, initial, where]) 返回給定軸上陣列元素的總和。
swapaxes(axis1, axis2) 返回一個軸 axis1axis2 互換的陣列檢視。
take(indices[, axis, out, mode]) 返回由給定索引處 a 元素組成的陣列。
tobytes([order]) 構造包含陣列中原始資料位元組的 Python 位元組。
tofile(fid[, sep, format]) 將陣列以文字或二進位制(預設)形式寫入檔案。
tolist() 將陣列作為 Python 標量的 a.ndim 級深巢狀列表返回。
tostring([order]) 一個與 tobytes 完全相同行為的相容別名。
trace([offset, axis1, axis2, dtype, out]) 返回陣列對角線上的總和。
transpose(*axes) 返回陣列的軸轉置檢視。
var([axis, dtype, out, ddof, keepdims, where]) 返回給定軸上陣列元素的方差。
view([dtype][, type]) 具有相同資料的陣列的新檢視。
dot
field

numpy.record

原文:numpy.org/doc/1.26/reference/generated/numpy.record.html

class numpy.record

資料型別標量,允許透過屬性查詢進行欄位訪問。

屬性:

T

與相應的陣列屬性相同的標量屬性。

base

基本物件

data

資料開頭的指標。

dtype

資料型別物件

flags

標誌的整數值

flat

標量的 1-D 檢視。

imag

標量的虛部。

itemsize

一個元素的位元組長度。

nbytes

標量的位元組長度。

ndim

陣列維度的數量。

real

標量的實部。

shape

陣列維度的元組。

size

元素數量的數量。

strides

位元組步驟的元組,每個維度。

方法

all 與相應的陣列屬性相同的標量方法。
any 與相應的陣列屬性相同的標量方法。
argmax 與相應的陣列屬性相同的標量方法。
argmin 與相應的陣列屬性相同的標量方法。
argsort 與相應的陣列屬性相同的標量方法。
astype 與相應的陣列屬性相同的標量方法。
byteswap 與相應的陣列屬性相同的標量方法。
choose 與相應的陣列屬性相同的標量方法。
clip 與相應的陣列屬性相同的標量方法。
compress 標量方法,與相應的陣列屬性相同。
conjugate 標量方法,與相應的陣列屬性相同。
copy 標量方法,與相應的陣列屬性相同。
cumprod 標量方法,與相應的陣列屬性相同。
cumsum 標量方法,與相應的陣列屬性相同。
diagonal 標量方法,與相應的陣列屬性相同。
dump 標量方法,與相應的陣列屬性相同。
dumps 標量方法,與相應的陣列屬性相同。
fill 標量方法,與相應的陣列屬性相同。
flatten 標量方法,與相應的陣列屬性相同。
getfield 標量方法,與相應的陣列屬性相同。
item 標量方法,與相應的陣列屬性相同。
itemset 標量方法,與相應的陣列屬性相同。
max 標量方法,與相應的陣列屬性相同。
mean 標量方法,與相應的陣列屬性相同。
min 標量方法,與相應的陣列屬性相同。
newbyteorder([new_order]) 返回一個具有不同位元組順序的新dtype
nonzero 標量方法,與相應的陣列屬性相同。
pprint() 高亮列印所有欄位。
prod 標量方法,與相應的陣列屬性相同。
ptp 與相應陣列屬性相同的標量方法。
put 與相應陣列屬性相同的標量方法。
ravel 與相應陣列屬性相同的標量方法。
repeat 與相應陣列屬性相同的標量方法。
reshape 與相應陣列屬性相同的標量方法。
resize 與相應陣列屬性相同的標量方法。
round 與相應陣列屬性相同的標量方法。
searchsorted 與相應陣列屬性相同的標量方法。
setfield 與相應陣列屬性相同的標量方法。
setflags 與相應陣列屬性相同的標量方法。
sort 與相應陣列屬性相同的標量方法。
squeeze 與相應陣列屬性相同的標量方法。
std 與相應陣列屬性相同的標量方法。
sum 與相應陣列屬性相同的標量方法。
swapaxes 與相應陣列屬性相同的標量方法。
take 與相應陣列屬性相同的標量方法。
tofile 與相應陣列屬性相同的標量方法。
tolist 與相應陣列屬性相同的標量方法。
tostring 與相應陣列屬性相同的標量方法。
trace 與相應陣列屬性相同的標量方法。
transpose 與相應的陣列屬性相同的標量方法。
var 與相應的陣列屬性相同的標量方法。
view 與相應的陣列屬性相同的標量方法。
結合
tobytes

numpy.lib.user_array.container

原文:numpy.org/doc/1.26/reference/generated/numpy.lib.user_array.container.html

class numpy.lib.user_array.container(data, dtype=None, copy=True)

用於簡單多重繼承的標準容器類。

方法

複製
轉為字串
位元組交換
轉換型別

numpy.ndarray.flat

原文:numpy.org/doc/1.26/reference/generated/numpy.ndarray.flat.html

屬性

ndarray.flat

陣列上的一維迭代器。

這是一個numpy.flatiter例項,表現類似於,但不是 Python 內建迭代器物件的子類。

另請參閱

flatten

返回陣列摺疊成一維後的副本。

flatiter

例子

>>> x = np.arange(1, 7).reshape(2, 3)
>>> x
array([[1, 2, 3],
 [4, 5, 6]])
>>> x.flat[3]
4
>>> x.T
array([[1, 4],
 [2, 5],
 [3, 6]])
>>> x.T.flat[3]
5
>>> type(x.flat)
<class 'numpy.flatiter'> 

一個賦值的示例:

>>> x.flat = 3; x
array([[3, 3, 3],
 [3, 3, 3]])
>>> x.flat[[1,4]] = 1; x
array([[3, 1, 3],
 [3, 1, 3]]) 

numpy.ndenumerate

原文:numpy.org/doc/1.26/reference/generated/numpy.ndenumerate.html

class numpy.ndenumerate(arr)

多維索引迭代器。

返回一個迭代器,產生陣列座標和值的對。

引數:

arrndarray

輸入陣列。

另請參閱

ndindex, flatiter

示例

>>> a = np.array([[1, 2], [3, 4]])
>>> for index, x in np.ndenumerate(a):
...     print(index, x)
(0, 0) 1
(0, 1) 2
(1, 0) 3
(1, 1) 4 

numpy.broadcast

原文:numpy.org/doc/1.26/reference/generated/numpy.broadcast.html

class numpy.broadcast

生成一個模擬廣播的物件。

引數:

in1, in2, …array_like

輸入引數。

返回:

b廣播物件

將輸入引數相互廣播,並返回一個封裝結果的物件。 其中包括shapend屬性,並且可以用作迭代器。

另請參閱

broadcast_arrays

broadcast_to

broadcast_shapes

示例

手動新增兩個向量,使用廣播:

>>> x = np.array([[1], [2], [3]])
>>> y = np.array([4, 5, 6])
>>> b = np.broadcast(x, y) 
>>> out = np.empty(b.shape)
>>> out.flat = [u+v for (u,v) in b]
>>> out
array([[5.,  6.,  7.],
 [6.,  7.,  8.],
 [7.,  8.,  9.]]) 

與內建廣播進行比較:

>>> x + y
array([[5, 6, 7],
 [6, 7, 8],
 [7, 8, 9]]) 

屬性:

index

廣播結果中的當前索引

iters

self“components”上的迭代器元組。

nd

廣播結果的維度數。

ndim

廣播結果的維度數。

numiter

廣播結果擁有的迭代器數量。

shape

廣播結果的形狀。

size

廣播結果的總大小。

方法

reset() 重置廣播結果的迭代器。

掩碼陣列

原文:numpy.org/doc/1.26/reference/maskedarray.html

掩碼陣列是可能具有缺失或無效條目的陣列。numpy.ma 模組提供了一個幾乎與 numpy 類似的替代品,支援帶有掩碼的資料陣列。

  • numpy.ma 模組

    • 原因

    • 什麼是掩碼陣列?

    • numpy.ma 模組

  • 使用 numpy.ma

    • 構建掩碼陣列

    • 訪問資料

    • 訪問掩碼

    • 僅訪問有效條目

    • 修改掩碼

    • 索引和切片

    • 掩碼陣列操作

  • 示例

    • 具有表示缺失資料的給定值的資料

    • 填充缺失資料

    • 數值操作

    • 忽略極端值

  • numpy.ma 模組的常量

    • masked

    • nomask

    • masked_print_option

  • MaskedArray

    • MaskedArray

    • 掩碼陣列的屬性和特性

  • MaskedArray 方法

    • 轉換

    • 形狀操作

    • 專案選擇和操作

    • 序列化和複製

    • 計算

    • 算術和比較操作

    • 表示

    • 特殊方法

    • 特定方法

  • 掩碼陣列操作

    • 常量

    • 建立

    • 檢查陣列

    • 操作 MaskedArray

    • 掩碼操作

    • 轉換操作

    • 掩碼陣列算術運算

numpy.ma 模組

原文:numpy.org/doc/1.26/reference/maskedarray.generic.html

原因

掩碼陣列是可能具有缺失或無效條目的陣列。numpy.ma 模組提供了一個幾乎與 numpy 類似的替代品,支援帶有掩碼的資料陣列。

什麼是掩碼陣列?

在許多情況下,資料集可能是不完整的或受到無效資料的影響。例如,感測器可能未能記錄資料,或記錄了無效值。numpy.ma 模組透過引入掩碼陣列提供了一種方便的解決此問題的方式。

掩碼陣列是標準numpy.ndarray和掩碼的組合。掩碼可以是nomask,表示關聯陣列的沒有值是無效的,或者是一個布林陣列,用於確定關聯陣列的每個元素是否有效。當掩碼的元素為False時,關聯陣列的相應元素是有效的,稱為未掩碼。當掩碼的元素為True時,關聯陣列的相應元素被稱為掩碼(無效)。

該包確保不使用掩碼條目進行計算。

舉個例子,讓我們考慮以下資料集:

>>> import numpy as np
>>> import numpy.ma as ma
>>> x = np.array([1, 2, 3, -1, 5]) 

我們希望將第四個條目標記為無效。最簡單的方法是建立一個掩碼陣列:

>>> mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0]) 

現在我們可以計算資料集的均值,而不考慮無效資料:

>>> mx.mean()
2.75 

numpy.ma 模組

numpy.ma 模組的主要特點是MaskedArray 類,它是numpy.ndarray的子類。該類及其屬性和方法在 MaskedArray 類部分中有更詳細的描述。

numpy.ma 模組可以作為numpy的補充使用:

>>> import numpy as np
>>> import numpy.ma as ma 

要建立一個使第二個元素無效的陣列,我們可以這樣做:

>>> y = ma.array([1, 2, 3], mask = [0, 1, 0]) 

要建立一個所有接近 1.e20 的值無效的掩碼陣列,我們可以這樣做:

>>> z = ma.masked_values([1.0, 1.e20, 3.0, 4.0], 1.e20) 

有關建立掩碼陣列的方法的完整討論,請參見構建掩碼陣列部分。

原因

掩碼陣列是可能具有缺失或無效條目的陣列。numpy.ma 模組提供了一個幾乎與 numpy 類似的替代品,支援帶有掩碼的資料陣列。

什麼是掩碼陣列?

在許多情況下,資料集可能是不完整的或受到無效資料的影響。例如,感測器可能未能記錄資料,或記錄了無效值。numpy.ma模組透過引入掩碼陣列提供了一種方便的解決此問題的方式。

一個掩碼陣列是標準numpy.ndarray和一個掩碼的組合。掩碼可以是nomask,表示關聯陣列的沒有值是無效的,或者是一個布林陣列,用於確定關聯陣列的每個元素是否有效。當掩碼的元素為False時,關聯陣列的相應元素是有效的,稱為未掩碼。當掩碼的元素為True時,關聯陣列的相應元素被稱為掩碼(無效)。

該包確保不使用掩碼條目進行計算。

舉個例子,讓我們考慮以下資料集:

>>> import numpy as np
>>> import numpy.ma as ma
>>> x = np.array([1, 2, 3, -1, 5]) 

我們希望將第四個條目標記為無效。最簡單的方法是建立一個掩碼陣列:

>>> mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0]) 

現在我們可以計算資料集的均值,而不考慮無效資料:

>>> mx.mean()
2.75 

numpy.ma模組

numpy.ma模組的主要特點是MaskedArray類,它是numpy.ndarray的子類。該類及其屬性和方法在 MaskedArray 類部分有更詳細的描述。

numpy.ma模組可以作為numpy的補充使用:

>>> import numpy as np
>>> import numpy.ma as ma 

建立一個第二個元素無效的陣列,我們可以這樣做:

>>> y = ma.array([1, 2, 3], mask = [0, 1, 0]) 

建立一個掩碼陣列,其中所有接近1.e20的值都是無效的,我們可以這樣做:

>>> z = ma.masked_values([1.0, 1.e20, 3.0, 4.0], 1.e20) 

有關建立掩碼陣列的方法的完整討論,請參見構建掩碼陣列部分。

使用 numpy.ma

構建掩碼陣列

有幾種方法可以構建掩碼陣列。

  • 第一種可能性是直接呼叫MaskedArray類。

  • 第二種可能性是使用兩個掩碼陣列建構函式,arraymasked_array

    array(data[, dtype, copy, order, mask, ...]) 一個可能包含掩碼值的陣列類。
    masked_array MaskedArray的別名
  • 第三個選項是檢視現有陣列的檢視。在這種情況下,如果陣列沒有命名欄位,則檢視的掩碼設定為nomask,否則為與陣列結構相同的布林陣列。

    >>> x = np.array([1, 2, 3])
    >>> x.view(ma.MaskedArray)
    masked_array(data=[1, 2, 3],
     mask=False,
     fill_value=999999)
    >>> x = np.array([(1, 1.), (2, 2.)], dtype=[('a',int), ('b', float)])
    >>> x.view(ma.MaskedArray)
    masked_array(data=[(1, 1.0), (2, 2.0)],
     mask=[(False, False), (False, False)],
     fill_value=(999999, 1.e+20),
     dtype=[('a', '<i8'), ('b', '<f8')]) 
    
  • 另一種可能性是使用以下任一函式:

    asarray(a[, dtype, order]) 將輸入轉換為給定資料型別的掩碼陣列。
    asanyarray(a[, dtype]) 將輸入轉換為掩碼陣列,保留子類。
    fix_invalid(a[, mask, copy, fill_value]) 返回輸入,使無效資料被掩碼並替換為填充值。
    masked_equal(x, value[, copy]) 掩碼一個等於給定值的陣列。
    masked_greater(x, value[, copy]) 掩碼一個大於給定值的陣列。
    masked_greater_equal(x, value[, copy]) 掩碼一個大於或等於給定值的陣列。
    masked_inside(x, v1, v2[, copy]) 掩碼在給定區間內的陣列。
    masked_invalid(a[, copy]) 掩碼出現無效值(NaN 或 infs)的陣列。
    masked_less(x, value[, copy]) 掩碼一個小於給定值的陣列。
    masked_less_equal(x, value[, copy]) 掩碼一個小於或等於給定值的陣列。
    masked_not_equal(x, value[, copy]) 掩碼一個等於給定值的陣列。
    masked_object(x, value[, copy, shrink]) 掩碼陣列x,其中資料與值完全相等。
    masked_outside(x, v1, v2[, copy]) 掩碼在給定區間外的陣列。
    masked_values(x, value[, rtol, atol, copy, ...]) 使用浮點數相等性進行掩碼。
    masked_where(condition, a[, copy]) 在滿足條件的情況下掩蓋陣列。

訪問資料

可以透過多種方式訪問掩碼陣列的底層資料:

  • 透過data屬性。輸出為numpy.ndarray或其子類的檢視,取決於掩碼陣列建立時底層資料的型別。

  • 透過__array__方法。然後輸出為numpy.ndarray

  • 直接將掩碼陣列視為numpy.ndarray或其子類之一(實際上使用data屬性時的操作)。

  • 透過getdata函式。

如果某些條目被標記為無效,則這些方法都不完全令人滿意。一般規則是,在需要表示陣列而沒有任何掩碼條目的情況下,建議使用filled方法填充陣列。

訪問掩碼

掩碼陣列的掩碼可透過其mask屬性訪問。必須記住,掩碼中的True條目表示無效資料。

另一種可能性是使用getmaskgetmaskarray函式。如果x是掩碼陣列,則getmask(x)輸出x的掩碼,否則輸出特殊值nomask。如果x沒有無效條目或不是掩碼陣列,則該函式輸出一個具有與x相同數量元素的False布林陣列。

僅訪問有效條目

要僅檢索有效條目,可以使用掩碼的反向作為索引。可以使用numpy.logical_not函式或簡單地使用~運算子來計算掩碼的反向:

>>> x = ma.array([[1, 2], [3, 4]], mask=[[0, 1], [1, 0]])
>>> x[~x.mask]
masked_array(data=[1, 4],
 mask=[False, False],
 fill_value=999999) 

另一種檢索有效資料的方法是使用compressed方法,它返回一個一維ndarray(或其子類之一,取決於baseclass屬性的值):

>>> x.compressed()
array([1, 4]) 

請注意,compressed的輸出始終為 1D。

修改掩碼

遮蔽條目

將一個或多個特定條目標記為無效的推薦方法是將特殊值masked分配給它們:

>>> x = ma.array([1, 2, 3])
>>> x[0] = ma.masked
>>> x
masked_array(data=[--, 2, 3],
 mask=[ True, False, False],
 fill_value=999999)
>>> y = ma.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> y[(0, 1, 2), (1, 2, 0)] = ma.masked
>>> y
masked_array(
 data=[[1, --, 3],
 [4, 5, --],
 [--, 8, 9]],
 mask=[[False,  True, False],
 [False, False,  True],
 [ True, False, False]],
 fill_value=999999)
>>> z = ma.array([1, 2, 3, 4])
>>> z[:-2] = ma.masked
>>> z
masked_array(data=[--, --, 3, 4],
 mask=[ True,  True, False, False],
 fill_value=999999) 

第二種可能性是直接修改mask,但不建議使用此方法。

注意

當使用簡單的非結構化資料型別建立新的掩碼陣列時,掩碼最初設定為特殊值nomask,大致對應於布林值False。嘗試設定nomask的元素將導致TypeError異常,因為布林值不支援專案賦值。

可以透過將True賦值給掩碼來一次性遮蔽陣列的所有條目:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x.mask = True
>>> x
masked_array(data=[--, --, --],
 mask=[ True,  True,  True],
 fill_value=999999,
 dtype=int64) 

最後,可以透過將一系列布林值賦給掩碼來遮蔽和/或解除遮蔽特定條目:

>>> x = ma.array([1, 2, 3])
>>> x.mask = [0, 1, 0]
>>> x
masked_array(data=[1, --, 3],
 mask=[False,  True, False],
 fill_value=999999) 

解除掩碼的條目

要解除一個或多個特定條目的掩碼,我們只需將一個或多個新的有效值分配給它們:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

注意

直接賦值解除掩碼的條目,如果掩碼陣列有掩碼,則會悄悄失敗,如hardmask屬性所示。此功能是為了防止覆蓋掩碼。要強制解除陣列具有硬掩碼的條目的掩碼,必須首先使用soften_mask方法軟化掩碼,然後再分配。可以使用harden_mask重新硬化:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1], hard_mask=True)
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.soften_mask()
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999)
>>> x.harden_mask()
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

要解除掩碼陣列的所有遮蔽條目(前提是掩碼不是硬掩碼),最簡單的解決方案是將常量nomask分配給掩碼:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.mask = ma.nomask
>>> x
masked_array(data=[1, 2, 3],
 mask=[False, False, False],
 fill_value=999999) 

索引和切片

由於MaskedArraynumpy.ndarray的子類,它繼承了其用於索引和切片的機制。

當訪問沒有命名欄位的掩碼陣列的單個條目時,輸出要麼是一個標量(如果掩碼的對應條目為False),要麼是特殊值masked(如果掩碼的對應條目為True):

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x[0]
1
>>> x[-1]
masked
>>> x[-1] is ma.masked
True 

如果掩碼陣列具有命名欄位,訪問單個條目會返回一個numpy.void物件,如果沒有欄位被掩碼,或者如果至少有一個欄位被掩碼,則返回一個與初始陣列相同 dtype 的 0d 掩碼陣列。

>>> y = ma.masked_array([(1,2), (3, 4)],
...                mask=[(0, 0), (0, 1)],
...               dtype=[('a', int), ('b', int)])
>>> y[0]
(1, 2)
>>> y[-1]
(3, --) 

當訪問切片時,輸出是一個掩碼陣列,其data屬性是原始資料的檢視,其掩碼要麼是nomask(如果原始陣列中沒有無效條目),要麼是原始掩碼對應切片的檢視。檢視是必需的,以確保任何對掩碼的修改傳播到原始資料。

>>> x = ma.array([1, 2, 3, 4, 5], mask=[0, 1, 0, 0, 1])
>>> mx = x[:3]
>>> mx
masked_array(data=[1, --, 3],
 mask=[False,  True, False],
 fill_value=999999)
>>> mx[1] = -1
>>> mx
masked_array(data=[1, -1, 3],
 mask=[False, False, False],
 fill_value=999999)
>>> x.mask
array([False, False, False, False,  True])
>>> x.data
array([ 1, -1,  3,  4,  5]) 

使用帶有結構化資料型別的掩碼陣列的欄位會返回一個MaskedArray

掩碼陣列的操作

掩碼陣列支援算術和比較操作。儘可能地,掩碼陣列的無效條目不會被處理,這意味著相應的data條目在操作之前和之後應該是相同的。

警告

我們需要強調這種行為可能不是系統的,掩碼資料在某些情況下可能會受到操作的影響,因此使用者不應依賴於這些資料保持不變。

numpy.ma模組提供了大多數 ufunc 的特定實現。具有有效域的一元和二元函式(如logdivide)在輸入被掩碼或超出有效域時返回masked常量:

>>> ma.log([-1, 0, 1, 2])
masked_array(data=[--, --, 0.0, 0.6931471805599453],
 mask=[ True,  True, False, False],
 fill_value=1e+20) 

掩碼陣列還支援標準的 numpy ufuncs。輸出結果是一個掩碼陣列。一元 ufunc 的結果在輸入被掩碼的地方也被掩碼。二元 ufunc 的結果在任何輸入被掩碼的地方也被掩碼。如果 ufunc 還返回可選的上下文輸出(包含 ufunc 名稱、其引數和其域的 3 元組),則上下文被處理,並且輸出掩碼陣列的條目在對應的輸入超出有效域的地方被掩碼:

>>> x = ma.array([-1, 1, 0, 2, 3], mask=[0, 0, 0, 0, 1])
>>> np.log(x)
masked_array(data=[--, 0.0, --, 0.6931471805599453, --],
 mask=[ True, False,  True, False,  True],
 fill_value=1e+20) 

構建掩碼陣列

有幾種構建掩碼陣列的方法。

  • 第一種可能性是直接呼叫MaskedArray類。

  • 第二種可能性是使用兩個掩碼陣列建構函式,arraymasked_array

    array(data[, dtype, copy, order, mask, ...]) 具有可能存在掩碼值的陣列類。
    masked_array MaskedArray 的別名
  • 第三種選擇是檢視現有陣列的檢視。在這種情況下,如果陣列沒有命名欄位,則檢視的掩碼設定為 nomask,否則��陣列結構相同的布林陣列。

    >>> x = np.array([1, 2, 3])
    >>> x.view(ma.MaskedArray)
    masked_array(data=[1, 2, 3],
     mask=False,
     fill_value=999999)
    >>> x = np.array([(1, 1.), (2, 2.)], dtype=[('a',int), ('b', float)])
    >>> x.view(ma.MaskedArray)
    masked_array(data=[(1, 1.0), (2, 2.0)],
     mask=[(False, False), (False, False)],
     fill_value=(999999, 1.e+20),
     dtype=[('a', '<i8'), ('b', '<f8')]) 
    
  • 還有另一種可能性是使用以下任一函式之一:

    asarray(a[, dtype, order]) 將輸入轉換為給定資料型別的掩碼陣列。
    asanyarray(a[, dtype]) 將輸入轉換為掩碼陣列,保留子類。
    fix_invalid(a[, mask, copy, fill_value]) 返回透過掩碼和用填充值替換的無效資料的輸入。
    masked_equal(x, value[, copy]) 對等於給定值的陣列進行掩碼處理。
    masked_greater(x, value[, copy]) 對大於給定值的陣列進行掩碼處理。
    masked_greater_equal(x, value[, copy]) 對大於或等於給定值的陣列進行掩碼處理。
    masked_inside(x, v1, v2[, copy]) 對給定區間內的陣列進行掩碼處理。
    masked_invalid(a[, copy]) 對出現無效值(NaN 或 inf)的陣列進行掩碼處理。
    masked_less(x, value[, copy]) 對小於給定值的陣列進行掩碼處理。
    masked_less_equal(x, value[, copy]) 對小於或等於給定值的陣列進行掩碼處理。
    masked_not_equal(x, value[, copy]) 對不等於給定值的陣列進行掩碼處理。
    masked_object(x, value[, copy, shrink]) 對陣列x中資料完全等於 value 的部分進行掩碼處理。
    masked_outside(x, v1, v2[, copy]) 對給定區間外的陣列進行掩碼處理。
    masked_values(x, value[, rtol, atol, copy, ...]) 使用浮點數相等性進行掩碼處理。
    masked_where(condition, a[, copy]) 在滿足條件的情況下對陣列進行掩碼處理。

訪問資料

掩碼陣列的底層資料可以透過多種方式訪問:

  • 透過data屬性。輸出是陣列的檢視,作為numpy.ndarray或其子類之一,取決於建立掩碼陣列時底層資料的型別。

  • 透過__array__方法。輸出是一個numpy.ndarray

  • 透過直接將掩碼陣列視為numpy.ndarray或其子類之一(實際上使用data屬性時所做的操作)。

  • 透過使用getdata函式。

如果一些條目被標記為無效,則這些方法都不完全令人滿意。一般規則是,在需要沒有任何掩碼條目的陣列表示時,建議使用filled方法填充陣列。

訪問掩碼

掩碼陣列的掩碼透過其mask屬性可訪問。我們必須記住,掩碼中的True條目表示無效資料。

另一種可能性是使用getmaskgetmaskarray函式。如果x是一個掩碼陣列,getmask(x)輸出x的掩碼,否則輸出特殊值nomaskgetmaskarray(x)輸出x的掩碼,如果x是一個掩碼陣列。如果x沒有無效條目或不是一個掩碼陣列,則該函式輸出一個具有與x相同數量元素的False布林陣列。

僅訪問有效條目

要僅檢索有效條目,我們可以使用遮罩的反向作為索引。可以使用numpy.logical_not函式或簡單地使用~運算子計算遮罩的反向:

>>> x = ma.array([[1, 2], [3, 4]], mask=[[0, 1], [1, 0]])
>>> x[~x.mask]
masked_array(data=[1, 4],
 mask=[False, False],
 fill_value=999999) 

檢索有效資料的另一種方法是使用compressed方法,該方法返回一個一維ndarray(或其子類之一,取決於baseclass屬性的值):

>>> x.compressed()
array([1, 4]) 

請注意,compressed的輸出始終為 1D。

修改遮罩

遮罩一個條目

推薦的標記一個或多個特定條目為無效的遮罩陣列的方法是將特殊值masked分配給它們:

>>> x = ma.array([1, 2, 3])
>>> x[0] = ma.masked
>>> x
masked_array(data=[--, 2, 3],
 mask=[ True, False, False],
 fill_value=999999)
>>> y = ma.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> y[(0, 1, 2), (1, 2, 0)] = ma.masked
>>> y
masked_array(
 data=[[1, --, 3],
 [4, 5, --],
 [--, 8, 9]],
 mask=[[False,  True, False],
 [False, False,  True],
 [ True, False, False]],
 fill_value=999999)
>>> z = ma.array([1, 2, 3, 4])
>>> z[:-2] = ma.masked
>>> z
masked_array(data=[--, --, 3, 4],
 mask=[ True,  True, False, False],
 fill_value=999999) 

第二種可能性是直接修改mask,但不建議使用此用法。

注意

當使用簡單的非結構化資料型別建立新的遮罩陣列時,遮罩最初設定為特殊值nomask,大致對應於布林值False。嘗試設定nomask的元素將導致TypeError異常,因為布林值不支援專案分配。

可以透過將True分配給遮罩一次性遮罩陣列的所有條目:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x.mask = True
>>> x
masked_array(data=[--, --, --],
 mask=[ True,  True,  True],
 fill_value=999999,
 dtype=int64) 

最後,可以透過將一系列布林值分配給掩碼來遮罩和/或取消遮罩特定條目:

>>> x = ma.array([1, 2, 3])
>>> x.mask = [0, 1, 0]
>>> x
masked_array(data=[1, --, 3],
 mask=[False,  True, False],
 fill_value=999999) 

取消遮罩一個條目

要取消遮罩一個或多個特定條目,只需將一個或多個新的有效值分配給它們:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

注意

透過直接分配來取消遮罩一個條目,如果遮罩陣列有遮罩,將會悄無聲息地失敗,如hardmask屬性所示。此功能是為了防止覆蓋遮罩而引入的。要強制取消遮罩一個條目,其中陣列有硬遮罩,必須首先使用soften_mask方法軟化遮罩,然後再分配。可以使用harden_mask重新硬化:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1], hard_mask=True)
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.soften_mask()
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999)
>>> x.harden_mask()
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

要取消遮罩遮罩陣列的所有遮罩條目(假設遮罩不是硬遮罩),最簡單的解決方案是將常量nomask分配給遮罩:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.mask = ma.nomask
>>> x
masked_array(data=[1, 2, 3],
 mask=[False, False, False],
 fill_value=999999) 

遮罩一個條目

將一個或多個特定條目標記為無效的推薦方法是將特殊值masked分配給它們:

>>> x = ma.array([1, 2, 3])
>>> x[0] = ma.masked
>>> x
masked_array(data=[--, 2, 3],
 mask=[ True, False, False],
 fill_value=999999)
>>> y = ma.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> y[(0, 1, 2), (1, 2, 0)] = ma.masked
>>> y
masked_array(
 data=[[1, --, 3],
 [4, 5, --],
 [--, 8, 9]],
 mask=[[False,  True, False],
 [False, False,  True],
 [ True, False, False]],
 fill_value=999999)
>>> z = ma.array([1, 2, 3, 4])
>>> z[:-2] = ma.masked
>>> z
masked_array(data=[--, --, 3, 4],
 mask=[ True,  True, False, False],
 fill_value=999999) 

第二種可能性是直接修改mask,但不建議這樣使用。

注意

當使用簡單的非結構化資料型別建立新的掩蓋陣列時,掩蓋最初設定為特殊值nomask,大致對應於布林值False。嘗試設定nomask的元素將導致TypeError異常,因為布林值不支援專案分配。

可以透過將True分配給掩蓋來一次性掩蓋陣列的所有條目:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x.mask = True
>>> x
masked_array(data=[--, --, --],
 mask=[ True,  True,  True],
 fill_value=999999,
 dtype=int64) 

最後,可以透過將一系列布林值分配給掩蓋來掩蓋和/或取消掩蓋特定條目:

>>> x = ma.array([1, 2, 3])
>>> x.mask = [0, 1, 0]
>>> x
masked_array(data=[1, --, 3],
 mask=[False,  True, False],
 fill_value=999999) 

取消掩蓋一個條目

要取消掩蓋一個或多個特定條目,我們只需將一個或多個新的有效值分配給它們:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

注意

如果掩蓋陣列具有掩蓋,則透過直接分配取消掩蓋一個條目將悄悄失敗,如hardmask屬性所示。此功能旨在防止覆蓋掩蓋。要強制取消掩蓋陣列具有硬掩蓋的條目,必須首先使用soften_mask方法軟化掩蓋,然後再分配。可以使用harden_mask重新硬化:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1], hard_mask=True)
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.soften_mask()
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x[-1] = 5
>>> x
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999)
>>> x.harden_mask()
masked_array(data=[1, 2, 5],
 mask=[False, False, False],
 fill_value=999999) 

要取消掩蓋陣列的所有掩蓋條目(假設掩蓋不是硬掩蓋),最簡單的解決方案是將常量nomask分配給掩蓋:

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x
masked_array(data=[1, 2, --],
 mask=[False, False,  True],
 fill_value=999999)
>>> x.mask = ma.nomask
>>> x
masked_array(data=[1, 2, 3],
 mask=[False, False, False],
 fill_value=999999) 

索引和切片

由於MaskedArraynumpy.ndarray的子類,它繼承了其用於索引和切片的機制。

當訪問沒有命名欄位的掩蓋陣列的單個條目時,輸出要麼是標量(如果掩蓋的相應條目為False),要麼是特殊值masked(如果掩蓋的相應條目為True):

>>> x = ma.array([1, 2, 3], mask=[0, 0, 1])
>>> x[0]
1
>>> x[-1]
masked
>>> x[-1] is ma.masked
True 

如果掩蓋陣列具有命名欄位,訪問單個條目將返回一個numpy.void物件,如果沒有欄位被掩蓋,或者如果至少有一個欄位被掩蓋,則返回一個與初始陣列相同 dtype 的 0d 掩蓋陣列。

>>> y = ma.masked_array([(1,2), (3, 4)],
...                mask=[(0, 0), (0, 1)],
...               dtype=[('a', int), ('b', int)])
>>> y[0]
(1, 2)
>>> y[-1]
(3, --) 

當訪問一個切片時,輸出是一個掩碼陣列,其data屬性是原始資料的檢視,其掩碼要麼是nomask(如果原始陣列中沒有無效條目),要麼是原始掩碼對應切片的檢視。檢視是必需的,以確保任何對掩碼的修改傳播到原始資料。

>>> x = ma.array([1, 2, 3, 4, 5], mask=[0, 1, 0, 0, 1])
>>> mx = x[:3]
>>> mx
masked_array(data=[1, --, 3],
 mask=[False,  True, False],
 fill_value=999999)
>>> mx[1] = -1
>>> mx
masked_array(data=[1, -1, 3],
 mask=[False, False, False],
 fill_value=999999)
>>> x.mask
array([False, False, False, False,  True])
>>> x.data
array([ 1, -1,  3,  4,  5]) 

使用結構化資料型別的掩碼陣列訪問欄位會返回一個MaskedArray

操作掩碼陣列

掩碼陣列支援算術和比較運算。儘可能地,掩碼陣列的無效條目不會被處理,這意味著相應的data條目在操作前後應該是相同的。

警告

我們需要強調這種行為可能不是系統性的,在某些情況下掩碼資料可能會受到操作的影響,因此使用者不應依賴於這些資料保持不變。

numpy.ma 模組提供了大多數 ufuncs 的特定實現。具有有效域的一元和二元函式(如logdivide)在輸入被掩碼或超出有效域時返回masked常量:

>>> ma.log([-1, 0, 1, 2])
masked_array(data=[--, --, 0.0, 0.6931471805599453],
 mask=[ True,  True, False, False],
 fill_value=1e+20) 

掩碼陣列還支援標準的 numpy ufuncs。輸出是一個掩碼陣列。一元 ufunc 的結果在輸入被掩碼的地方也被掩碼。二元 ufunc 的結果在任何輸入被掩碼的地方也被掩碼。如果 ufunc 還返回可選的上下文輸出(包含 ufunc 名稱、其引數和其域的 3 元組),則上下文會被處理,並且輸出掩碼陣列的條目在對應輸入超出有效域的地方也被掩碼:

>>> x = ma.array([-1, 1, 0, 2, 3], mask=[0, 0, 0, 0, 1])
>>> np.log(x)
masked_array(data=[--, 0.0, --, 0.6931471805599453, --],
 mask=[ True, False,  True, False,  True],
 fill_value=1e+20) 

示例

具有表示缺失資料的給定值的資料

讓我們考慮一個元素列表 x,其中值為 -9999 代表缺失資料。我們希望計算資料的平均值和異常向量(與平均值的偏差):

>>> import numpy.ma as ma
>>> x = [0.,1.,-9999.,3.,4.]
>>> mx = ma.masked_values (x, -9999.)
>>> print(mx.mean())
2.0
>>> print(mx - mx.mean())
[-2.0 -1.0 -- 1.0 2.0]
>>> print(mx.anom())
[-2.0 -1.0 -- 1.0 2.0] 

填補缺失資料

現在假設我們希望列印相同的資料,但將缺失值替換為平均值。

>>> print(mx.filled(mx.mean()))
[0\.  1\.  2\.  3\.  4.] 

數值運算

數值運算可以輕鬆進行,無需擔心缺失值、除以零、負數的平方根等問題:

>>> import numpy.ma as ma
>>> x = ma.array([1., -1., 3., 4., 5., 6.], mask=[0,0,0,0,1,0])
>>> y = ma.array([1., 2., 0., 4., 5., 6.], mask=[0,0,0,0,0,1])
>>> print(ma.sqrt(x/y))
[1.0 -- -- 1.0 -- --] 

輸出的四個值是無效的:第一個來自對負數取平方根,第二個來自除以零,最後兩個是輸入被掩碼的情況。

忽略極端值

假設我們有一個浮點數陣列d,取值範圍在 0 到 1 之間。我們希望計算d的值的平均值,同時忽略範圍在[0.2, 0.9]之外的任何資料:

>>> d = np.linspace(0, 1, 20)
>>> print(d.mean() - ma.masked_outside(d, 0.2, 0.9).mean())
-0.05263157894736836 

具有表示缺失資料的給定值的資料

假設我們有一個元素列表x,其中數值為-9999 表示缺失資料。我們希望計算資料的平均值和異常向量(與平均值的偏差):

>>> import numpy.ma as ma
>>> x = [0.,1.,-9999.,3.,4.]
>>> mx = ma.masked_values (x, -9999.)
>>> print(mx.mean())
2.0
>>> print(mx - mx.mean())
[-2.0 -1.0 -- 1.0 2.0]
>>> print(mx.anom())
[-2.0 -1.0 -- 1.0 2.0] 

填充缺失資料

現在假設我們希望列印相同的資料,但將缺失值替換為平均值。

>>> print(mx.filled(mx.mean()))
[0\.  1\.  2\.  3\.  4.] 

數值運算

數值運算可以輕鬆進行,無需擔心缺失值、除以零、負數的平方根等:

>>> import numpy.ma as ma
>>> x = ma.array([1., -1., 3., 4., 5., 6.], mask=[0,0,0,0,1,0])
>>> y = ma.array([1., 2., 0., 4., 5., 6.], mask=[0,0,0,0,0,1])
>>> print(ma.sqrt(x/y))
[1.0 -- -- 1.0 -- --] 

輸出的四個值是無效的:第一個來自於對負數開平方,第二個來自於除以零,最後兩個是輸入被遮蔽的情況。

忽略極端值

假設我們有一個浮點數陣列d,取值範圍在 0 到 1 之間。我們希望計算d的值的平均值,同時忽略範圍在[0.2, 0.9]之外的任何資料:

>>> d = np.linspace(0, 1, 20)
>>> print(d.mean() - ma.masked_outside(d, 0.2, 0.9).mean())
-0.05263157894736836 

相關文章