Большая проблема для практики array-slicing
в многомерные тензоры/массивы!
Мы будем инициализировать выходной массив как многомерный массив 6D
и просто разрезать его и назначить четыре массива, которые будут изменены как массивы 4D
. Цель состоит в том, чтобы избежать какой-либо укладки/конкатенации, поскольку они были бы дорогими, особенно при работе с большими массивами, вместо этого работая с изменением входных массивов, что было бы просто просмотром.
Вот реализация -
out = np.zeros((N,2,3,N,2,3),dtype=A.dtype)
out[:,0,:,:,0,:] = A.reshape(N,3,N,3)
out[:,0,:,:,1,:] = D.reshape(N,3,N,3)
out[:,1,:,:,0,:] = C.reshape(N,3,N,3)
out[:,1,:,:,1,:] = B.reshape(N,3,N,3)
out.shape = (6*N,6*N)
Просто объяснить немного больше, мы имели:
|------------------------ Axes for selecting A, B, C, D
np.zeros((N,2,3,N,2,3),dtype=A.dtype)
|------------------------- Axes for selecting A, B, C, D
Таким образом, были использованы эти две оси (второй и пятый) длин (2x2) = 4
, чтобы выбрать между четыре входа.
время выполнения теста
подходы -
def original_app(A, B, C, D):
final = np.zeros((6*N,6*N),dtype=A.dtype)
for i in range(N):
for j in range(N):
for k in range(3):
for l in range(3):
final[6*i + k][6*j + l] = A[3*i+k][3*j+l]
final[6*i + k + 3][6*j + l + 3] = B[3*i+k][3*j+l]
final[6*i + k + 3][6*j + l] = C[3*i+k][3*j+l]
final[6*i + k][6*j + l + 3] = D[3*i+k][3*j+l]
return final
def slicing_app(A, B, C, D):
out = np.zeros((N,2,3,N,2,3),dtype=A.dtype)
out[:,0,:,:,0,:] = A.reshape(N,3,N,3)
out[:,0,:,:,1,:] = D.reshape(N,3,N,3)
out[:,1,:,:,0,:] = C.reshape(N,3,N,3)
out[:,1,:,:,1,:] = B.reshape(N,3,N,3)
return out.reshape(6*N,6*N)
тайминги и верификация -
In [147]: # Setup input arrays
...: N = 200
...: A = np.random.randint(11,99,(3*N,3*N))
...: B = np.random.randint(11,99,(3*N,3*N))
...: C = np.random.randint(11,99,(3*N,3*N))
...: D = np.random.randint(11,99,(3*N,3*N))
...:
In [148]: np.allclose(slicing_app(A, B, C, D), original_app(A, B, C, D))
Out[148]: True
In [149]: %timeit original_app(A, B, C, D)
1 loops, best of 3: 1.63 s per loop
In [150]: %timeit slicing_app(A, B, C, D)
100 loops, best of 3: 9.26 ms per loop
(не по теме) | Я думал про себя: единственный раз, когда я слышал, кто-то сказал, что «numpythonic» был кем-то другим. Но потом я проверил, и это был ты тоже :) – miradulo
@Mitch Почти * тоник *. – Divakar
Да, я сражаюсь с разными способами создания для циклов в Numpythonic. Глаз - ошибка, он должен быть нулевым. – NunodeSousa