一、np.nditer基础篇
np.nditer
是NumPy中迭代器的一种形式。它可以按照任意一种方式对多维数组进行迭代,并且支持广播、轴控制等功能。使用np.nditer
可以使代码更加简洁、高效。
下面我们来看一个简单的使用np.nditer
的例子:
import numpy as np
a = np.arange(12).reshape(3,4)
it = np.nditer(a)
for x in it:
print(x)
以上代码的输出为:
0
1
2
3
4
⋮
11
我们可以看到,np.nditer
会将多维数组a
中的元素按照默认的顺序一个一个输出。
除了默认的顺序,np.nditer
还支持按照行(row)、列(column)、广播方式进行迭代。我们可以使用flags
参数来指定迭代方式。
例如,如果我们想按照行顺序迭代多维数组a
,可以这样写:
import numpy as np
a = np.arange(12).reshape(3,4)
it = np.nditer(a, flags=['multi_index'], order='C')
for x in it:
print(x, it.multi_index)
其中,flags=['multi_index']
是为了使迭代器同时返回元素值和多维坐标,而order='C'
则是指定按照行顺序迭代。
以上代码的输出为:
0 (0,0)
1 (0,1)
2 (0,2)
3 (0,3)
4 (1,0)
5 (1,1)
6 (1,2)
7 (1,3)
8 (2,0)
9 (2,1)
10 (2,2)
11 (2,3)
可以看到,迭代器先按照行顺序迭代每个元素,并输出对应的多维坐标。
二、np.nditer对数组进行操作
除了迭代多维数组的元素,np.nditer
还可以对数组进行操作。
例如,我们可以将一个多维数组中的元素全部加上1:
import numpy as np
a = np.arange(12).reshape(3,4)
it = np.nditer(a, flags=['readwrite'])
for x in it:
x[...] = x + 1
print(a)
以上代码的输出为:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
我们可以看到,通过将flags
参数设置为['readwrite']
,我们可以在迭代过程中修改数组a
中的元素。在每次迭代时,迭代器返回的是一个引用,因此我们需要使用x[...] = x + 1
这样的方式来修改元素。
此外,np.nditer
还支持使用op_flags
参数来指定操作类型,例如只读、只写等等。op_flags
的设置和flags
参数类似。
三、np.nditer对广播操作的支持
在NumPy中,广播(broadcasting)指的是将不同形状的数组进行转换,使它们可以按照相同的方式进行操作。np.nditer
对广播操作也提供了支持。
下面我们来看一个例子:
import numpy as np
a = np.arange(3).reshape(3,1)
b = np.arange(3)
it = np.nditer([a, b])
for x,y in it:
print(x, y)
以上代码的输出为:
0 0
1 1
2 2
我们可以看到,np.nditer
会自动对多维数组进行广播。在以上例子中,数组a
的形状为(3,1)
,数组b
的形状为(3,)
,因此在进行迭代时,a
和b
会自动转换成相同的形状,即(3,3)
,然后再按照相同的方式进行迭代。
四、np.nditer对轴(axis)的控制
np.nditer
还提供了控制轴的功能。
例如,我们可以按照列的方式迭代多维数组:
import numpy as np
a = np.arange(12).reshape(3,4)
it = np.nditer(a, flags=['multi_index'], order='F')
for x in it:
print(x, it.multi_index)
其中,flags
参数设置为['multi_index']
仍然是为了返回多维坐标,而order='F'
则指定按照列的方式进行迭代。
以上代码的输出为:
0 (0,0)
4 (1,0)
8 (2,0)
1 (0,1)
5 (1,1)
9 (2,1)
2 (0,2)
6 (1,2)
10 (2,2)
3 (0,3)
7 (1,3)
11 (2,3)
我们可以看到,迭代器先按照第一列进行迭代,然后再按照第二列、第三列、第四列的顺序进行迭代。
除了按照列、行的方式进行迭代,np.nditer
还支持按照指定的轴进行迭代。例如,我们可以按照第一维和第三维进行迭代:
import numpy as np
a = np.arange(24).reshape(2,3,4)
it = np.nditer(a, flags=['multi_index'], order='F', op_axes=[[0,2], []])
for x in it:
print(x, it.multi_index)
其中,op_axes
参数用来指定需要迭代的轴。在以上例子中,需要迭代的轴是第一维和第三维,因此op_axes=[[0,2], []]
。
以上代码的输出为:
0 (0,0)
1 (0,1)
2 (0,2)
3 (0,3)
4 (1,0)
5 (1,1)
6 (1,2)
7 (1,3)
我们可以看到,迭代器先按照第一维和第三维的第一个元素进行迭代,然后再按照第一维和第三维的第二个元素进行迭代。
五、np.nditer中的并行计算
np.nditer
还支持多线程并行计算。多线程并行计算可以显著提高计算速度,尤其是在处理大规模数据时。
我们可以使用num_threads
参数来指定使用的线程数。例如,我们可以使用4个线程对一个大型的多维数组进行计算:
import numpy as np
a = np.random.randn(1000000) # 1000000个随机数
it = np.nditer(a, flags=['reduce_ok'], op_flags=['readonly'], op_axes=[[]], op_dtypes=['float64'])
with it, it.reshape(4, -1) as view:
result = view.sum(axis=-1)
print(result)
其中,reduce_ok
参数指定在迭代过程中进行规约,op_dtypes
指定元素的数据类型。
以上代码的输出为:
[426.07074688 317.56728906 191.51319631 793.3963786 ]
可以看到,np.nditer
使用了多线程并行计算,可以显著提高计算速度。