NumPy遍历数组
NumPy 提供了一个 nditer 迭代器对象,它可以配合 for 循环完成对数组元素的遍历。
下面看一组示例,使用 arange() 函数创建一个 3*4 数组,并使用 nditer 生成迭代器对象。
示例1:
在默认情况下,当我们遍历数组中元素的时候,不需要考虑数组的存储顺序,这一点可以通过遍历上述数组的转置数组来验证。
示例 2:
下面以 C 样式访问转置数组的副本。示例 3 如下:
示例如下:
示例 6 如下:
假设数组 a 的维度是 3*4,另一个数组 b 的维度是 1*4 (即维度较小的数组 b 可以被广播到数组 a 中),示例如下:
下面看一组示例,使用 arange() 函数创建一个 3*4 数组,并使用 nditer 生成迭代器对象。
示例1:
import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) #使用nditer迭代器,并使用for进行遍历 for x in np.nditer(a): print(x)输出结果:
0 5 10 15 20 25 30 35 40 45 50 55
遍历顺序
在内存中,Numpy 数组提供了两种存储数据的方式,分别是 C-order(行优先顺序)与 Fortrant-order(列优先顺序)。那么 nditer 迭代器又是如何处理具有特定存储顺序的数组呢?其实它选择了一种与数组内存布局一致的顺序,之所以这样做,是为了提升数据的访问效率。在默认情况下,当我们遍历数组中元素的时候,不需要考虑数组的存储顺序,这一点可以通过遍历上述数组的转置数组来验证。
示例 2:
import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) #a的转置数组 b = a.T print (b) for x in np.nditer(b): print(x,end=",")输出结果:
#转置数组b [[ 0 20 40] [ 5 25 45] [10 30 50] [15 35 55]] #a转置后的遍历输出 0 5 10 15 20 25 30 35 40 45 50 55从示例 1、2 的输出结果可以看出,a 和 a.T 的遍历顺序是一样的,也就是说,它们在内存中的存储顺序是一样的。
下面以 C 样式访问转置数组的副本。示例 3 如下:
import numpy as np a = np.arange(0,60,5).reshape(3,4) #copy方法生成数组副本 for x in np.nditer(a.T.copy(order='C')): print (x, end=", " )输出结果:
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55,
通过示例 3 可知 a.T.copy(order = 'C') 的遍历结果与示例 1、2 的数组遍历结果不一样。究其原因,就是因为它们在内存中的存储方式不一样。指定遍历顺序
您可以通过 nditer 对象的order
参数来指定数组的遍历的顺序。示例 4 如下:import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) print(a) for x in np.nditer(a, order = 'C'): print (x,end=",") for x in np.nditer(a, order = 'F'): print (x,end=",")输出结果如下:
#c=order行顺序 0,5,10,15,20,25,30,35,40,45,50,55, #F-order列顺序 0,20,40,5,25,45,10,30,50,15,35,55,
修改数组元素值
nditer 对象提供了一个可选参数op_flags
,它表示能否在遍历数组时对元素进行修改。它提供了三种模式,如下所示:1) read-only
只读模式,在这种模式下,遍历时不能修改数组中的元素。2) read-write
读写模式,遍历时可以修改元素值。3) write-only
只写模式,在遍历时可以修改元素值。示例如下:
import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) print ("原数组是:",a) for x in np.nditer(a, op_flags=['readwrite']): x[...]=2*x print ('修改后的数组是:',a)最后输出结果如下:
原数组是: [[ 0 5 10 15] [20 25 30 35] [40 45 50 55]] 修改后的数组是: [[ 0 10 20 30] [ 40 50 60 70] [ 80 90 100 110]]
外部循环使用
nditer 对象的构造函数有一个“flags”参数,它可以接受以下参数值(了解即可):参数值 | 描述说明 |
---|---|
c_index | 可以跟踪 C 顺序的索引。 |
f_index | 可以跟踪 Fortran 顺序的索引。 |
multi_index | 每次迭代都会跟踪一种索引类型。 |
external_loop | 返回的遍历结果是具有多个值的一维数组。 |
import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) print("原数组",a) #修改后数组 for x in np.nditer(a, flags = ['external_loop'], order = 'F'): print(x)结果输出:
原数组: [[ 0 5 10 15] [20 25 30 35] [40 45 50 55]] #修改后的一维数组 [ 0 20 40] [ 5 25 45] [10 30 50] [15 35 55]
迭代多个数组
如果两个数组都能够被广播,那么 nditer 对象就可以同时对它们迭代。假设数组 a 的维度是 3*4,另一个数组 b 的维度是 1*4 (即维度较小的数组 b 可以被广播到数组 a 中),示例如下:
import numpy as np a = np.arange(0,60,5) a = a.reshape(3,4) print (a) b = np.array([1, 2, 3, 4], dtype = int) print (b) #广播迭代 for x,y in np.nditer([a,b]): print ("%d:%d" % (x,y),end=",")输出结果是:
0:1,5:2,10:3,15:4,20:1,25:2,30:3,35:4,40:1,45:2,50:3,55:4,