Numpy 遍歷數(shù)組
Numpy 提供了一個迭代器對象 numpy.nditer
,能夠實現(xiàn)靈活地訪問一個或者多個數(shù)組元素,達到遍歷數(shù)組的目的。
1. 數(shù)組元素訪問
1.1 按照內存布局打印數(shù)組元素
在默認情況下,numpy.nditer
迭代器返回的元素順序,是和數(shù)組內存布局一致的,這樣做是為了提升訪問的效率,默認是行序優(yōu)先。
案例
例如,我們對于新創(chuàng)建的 2×3 的數(shù)組,利用 nditer 迭代器進行順序訪問:
arr = np.arange(6).reshape(2,3)
arr
Out:
array([[0, 1, 2],
[3, 4, 5]])
for i in np.nditer(arr):
print(i, end=" ")
打印結果為:
0 1 2 3 4 5
可以看到,在不增加其他設置的情況下,默認的打印順序是行序優(yōu)先(即 C-order)。
在不改變內部布局的情況下,通過該方式進行遍歷,并不會改變順序,例如我們通過迭代上述數(shù)組的轉置來證明這一點。
for i in np.nditer(arr.T):
print(i, end=" ")
打印結果為:
0 1 2 3 4 5
從上述結果可以看出,轉置方法并未改變數(shù)組元素的存儲順序。
相對應的,我們利用 copy
方法,顯式地更改內存順序,nditer 迭代器的遍歷解雇也會發(fā)生響應的變化:
for i in np.nditer(arr.T.copy("C")):
print(i, end=" ")
打印結果為:
0 3 1 4 2 5
1.2 控制遍歷順序
如果想要改變遍歷的順序,一種是上面案例中提到的,利用 copy
方法來修改內存順序。當然,nditer 也提供了 order
參數(shù)來達到同樣的目的。
案例
C order,即是行序優(yōu)先,跟默認的遍歷順序一致。
print ('以 C 風格順序排序:')
for i in np.nditer(arr, order="C"):
print(i, end=" ")
打印結果為:
以 C 風格順序排序:
0 1 2 3 4 5
Fortran order,即是列序優(yōu)先:
print ('以 F 風格順序排序:')
for i in np.nditer(arr, order="F"):
print(i, end=" ")
打印結果為:
以 F 風格順序排序:
0 3 1 4 2 5
2. 數(shù)組元素修改
nditer 對象有另一個可選參數(shù) op_flags
。 默認情況下,nditer 將視待迭代遍歷的數(shù)組為只讀對象(read-only),為了在遍歷數(shù)組的同時,實現(xiàn)對數(shù)組元素值得修改,必須指定 read-write 或者 write-only 的模式。
案例
在遍歷的時候,對數(shù)組進行平方計算,生成一個特殊的平方方陣。
arr1 = np.arange(16).reshape(4,4)
arr1
Out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
# 指定讀寫模式
for i in np.nditer(arr1, op_flags=["readwrite"]):
i[...] = i**2
arr1
Out:
array([[ 0, 1, 4, 9],
[ 16, 25, 36, 49],
[ 64, 81, 100, 121],
[144, 169, 196, 225]])
在讀寫模式下,arr1 數(shù)組發(fā)生了變化。
3. flags 可選參數(shù)
flags
參數(shù)可以接受傳入一個數(shù)組或元組,它可以接受下列值:
參數(shù) | 描述 |
---|---|
c_index | 可以跟蹤 C 順序的索引 |
f_index | 可以跟蹤 Fortran 順序的索引 |
multi-index | 每次迭代可以跟蹤多重索引類型 |
external_loop | 給出的值是具有多個值的一維數(shù)組,而不是零維數(shù)組 |
3.1 可以跟蹤 C 順序的索引
跟 list
類似,每個元素都對應有相應的 id。在按照 C 順序跟蹤索引的時候,數(shù)組的索引可以按照下圖來直觀理解:
上述索引的標注是按照行優(yōu)先的順序進行的。
案例
設置 flags=["c_index"]
,可以實現(xiàn)類似 list 的 enumerate
函數(shù)的效果:
cit = np.nditer(arr, flags=["c_index"])
while not cit.finished:
print("value:", cit[0], "index:<{}>".format(cit.index))
cit.iternext()
打印結果為:
value: 0 index:<0>
value: 1 index:<1>
value: 2 index:<2>
value: 3 index:<3>
value: 4 index:<4>
value: 5 index:<5>
在上述代碼中,同過 while
循環(huán)可以逐步打印出每個元素的值和索引。
3.2 可以跟蹤 Fortran 順序的索引
在按照 F 順序跟蹤索引的時候,數(shù)組的索引可以按照下圖來直觀理解:
F 順序即列優(yōu)先的順序。
案例
想要實現(xiàn)該索引順序,可以設置 flags=["f_index"]
:
fit = np.nditer(arr, flags=["f_index"])
while not fit.finished:
print("value:", fit[0], "index:<{}>".format(fit.index))
fit.iternext()
打印結果為:
value: 0 index:<0>
value: 1 index:<2>
value: 2 index:<4>
value: 3 index:<1>
value: 4 index:<3>
value: 5 index:<5>
可以發(fā)現(xiàn),在順序打印該索引結構的時候,默認是按照行優(yōu)先的順序打印的。
也就是說,在打印索引結構的時候,打印的順序是一樣的,不同的地方在于,c_index
和 f_index
索引標注的順序不一樣。
3.3 多重索引
對于 arr 這樣的二維數(shù)組,可以用 2 個維度(x 方向和 y 方向)的序列來唯一定位每一個元素,multi-index
則可以打印出該種索引順序。
multi_index
索引類型可以按照下圖來直觀理解:
案例
設置 flags=["multi_index"]
,效果如下:
mul_it = np.nditer(arr, flags=['multi_index'])
while not mul_it.finished:
print("value:", mul_it[0], "index:<{}>".format(mul_it.multi_index))
mul_it.iternext()
打印結果為:
value: 0 index:<(0, 0)>
value: 1 index:<(0, 1)>
value: 2 index:<(0, 2)>
value: 3 index:<(1, 0)>
value: 4 index:<(1, 1)>
value: 5 index:<(1, 2)>
3.4 遍歷返回一維數(shù)組
將一維的最內層的循環(huán)轉移到外部循環(huán)迭代器,使得 NumPy 的矢量化操作在處理更大規(guī)模數(shù)據(jù)時變得更有效率。簡單來說,當指定 flags=['external_loop']
時,將返回一維數(shù)組而并非單個元素。
具體來說,當 ndarray 的順序和遍歷的順序一致時,將所有元素組成一個一維數(shù)組返回;當 ndarray 的順序和遍歷的順序不一致時,返回每次遍歷的一維數(shù)組。
下面通過具體案例來理解這句話:
案例
對于上述創(chuàng)建的 arr,是行優(yōu)先順序的數(shù)組。當我們指定遍歷順序為C(行優(yōu)先,與定義的順序一致),指定 flags=["external_loop"]
,則有:
for i in np.nditer(arr, flags=['external_loop'], order='C'):
print(i)
打印結果為:
[0 1 2 3 4 5]
可以看到,該案例中,把全部元素組成一個一維數(shù)組,并返回。
案例
當我們指定遍歷順序為F(列優(yōu)先),指定 flags=["external_loop"]
,則有:
for i in np.nditer(arr, flags=['external_loop'], order='F'):
print(i)
打印結果為:
[0 3]
[1 4]
[2 5]
可以看到,該案例中,返回每次遍歷的一維數(shù)組。
4. 小結
本節(jié)主要介紹了如何利用 Numpy 內置的迭代器對象 numpy.nditer,實現(xiàn)靈活地遍歷數(shù)組中的元素。numpy.nditer 迭代器提供了 order
參數(shù),來控制訪問的順序;提供了 op_flags
參數(shù),來設置只讀或讀寫模式;提供 flags 參數(shù)來同步返回數(shù)組索引,功能非常強大。