I have a 3d matrix of shape (7,4,6) where 4x6 is (rows x columns) and 7 is the number of frames/layers. I want to iterate each layer over each values in 4x6. However the loop always gives an index error if I change the order of loop from (frames, rows, columns) to (rows, columns, frames). The code I used is:
>>> array.shape
(7, 4, 6)
>>> for i in range(0,4):
... for j in range(0,6):
... for k in range(0,7):
... print(array[i][j][k])
I want the frames to be the innermost loop but I get an index error when I run the above code. Any suggestions on how can I modify the above code?
3 Answers 3
numpy has a function for this: np.nditer:
>>> array = np.random.randint(0, 10, size = (3,4,5))
>>> array.shape
(3, 4, 5)
>>> array
array([[[8, 8, 0, 6, 0],
[9, 4, 6, 6, 1],
[4, 3, 1, 3, 6],
[2, 4, 4, 3, 9]],
[[3, 5, 3, 9, 6],
[8, 0, 8, 5, 3],
[4, 8, 6, 2, 7],
[2, 7, 1, 8, 4]],
[[5, 7, 5, 6, 7],
[7, 4, 2, 7, 0],
[5, 6, 7, 9, 7],
[7, 2, 7, 7, 4]]])
>>> for elem in np.nditer(array):
... print(elem, end=' ')
8 8 0 6 0 9 4 6 6 1 4 3 1 3 6 2 4 4 3 9 3 5 3 9 6 8 0 8 5 3 4 8 6 2 7 2 7 1 8 4 5 7 5 6 7 7 4 2 7 0 5 6 7 9 7 7 2 7 7 4
If you want to print them in different order, use the order flag:
>>> for idx in np.nditer(array, order='F'):
... print(idx, end = ' ')
8 3 5 9 8 7 4 4 5 2 2 7 8 5 7 4 0 4 3 8 6 4 7 2 0 3 5 6 8 2 1 6 7 4 1 7 6 9 6 6 5 7 3 2 9 3 8 7 0 6 7 1 3 0 6 7 7 9 4 4
If you want the indices, you can use np.ndindex:
>>> for idx in np.ndindex(array.shape):
... print(array[idx], end=' ')
8 8 0 6 0 9 4 6 6 1 4 3 1 3 6 2 4 4 3 9 3 5 3 9 6 8 0 8 5 3 4 8 6 2 7 2 7 1 8 4 5 7 5 6 7 7 4 2 7 0 5 6 7 9 7 7 2 7 7 4
np.ndindex gives indices as tuples:
>>> for idx in np.ndindex(array.shape):
... print(idx, end=' ')
(0, 0, 0) (0, 0, 1) (0, 0, 2) (0, 0, 3) (0, 0, 4) (0, 1, 0) (0, 1, 1) (0, 1, 2) (0, 1, 3) (0, 1, 4) (0, 2, 0) (0, 2, 1) (0, 2, 2) (0, 2, 3) (0, 2, 4) (0, 3, 0) (0, 3, 1) (0, 3, 2) (0, 3, 3) (0, 3, 4) (1, 0, 0) (1, 0, 1) (1, 0, 2) (1, 0, 3) (1, 0, 4) (1, 1, 0) (1, 1, 1) (1, 1, 2) (1, 1, 3) (1, 1, 4) (1, 2, 0) (1, 2, 1) (1, 2, 2) (1, 2, 3) (1, 2, 4) (1, 3, 0) (1, 3, 1) (1, 3, 2) (1, 3, 3) (1, 3, 4) (2, 0, 0) (2, 0, 1) (2, 0, 2) (2, 0, 3) (2, 0, 4) (2, 1, 0) (2, 1, 1) (2, 1, 2) (2, 1, 3) (2, 1, 4) (2, 2, 0) (2, 2, 1) (2, 2, 2) (2, 2, 3) (2, 2, 4) (2, 3, 0) (2, 3, 1) (2, 3, 2) (2, 3, 3) (2, 3, 4)
2 Comments
You should use the following:
>>> array.shape
(7, 4, 6)
>>> for j in range(4):
... for k in range(6):
... for i in range(7):
... print(array[i][j][k])
You are using the wrong indexers in your original code.
Comments
A more elegant and pythonic way of doing that could be using itertools module.
from itertools import product
def using_itertools(array):
X, Y, Z = array.shape
for x, y, z in product(range(X), range(Y), range(Z)):
print(array[x,y,z])
def using_forloop(array):
X, Y, Z = array.shape
for k in range(Z):
for j in range(Y):
for i in range(X):
print(array[i][j][k])
Although the first approach looks clean, speed-wise I found both to be similar.
0is redundant. you can simply write in range(4),range(5) and range(7). Second, I think the order need to be 7,4,6 and not what you wrotenp.ravelto "flatten" the array to 1D.array.flatten()itself.print(array[k ,i ,j])because it is more readable and faster.