Подход № 1
Адаптация strided-based
решения из тех же связанных вопросов и ответов для производительности -
from skimage.util.shape import view_as_windows
def roll_along_second_axis_3dar(a, r):
r = np.asarray(r)
a_ext = np.concatenate((a,a[:,:-1,:]),axis=1)
n = a.shape[1]
idx = (n-r)%n
w = view_as_windows(a_ext,(1,n,1))[...,0,:,0]
return w[np.arange(len(idx)),idx].swapaxes(1,2)
Пробный прогон -
In [11]: a
Out[11]:
array([[[44, 47, 64],
[67, 67, 9],
[83, 21, 36],
[87, 70, 88]],
[[88, 12, 58],
[65, 39, 87],
[46, 88, 81],
[37, 25, 77]]])
In [12]: roll_along_second_axis_3dar(a, r=[-1,1])
Out[12]:
array([[[67, 67, 9],
[83, 21, 36],
[87, 70, 88],
[44, 47, 64]],
[[37, 25, 77],
[88, 12, 58],
[65, 39, 87],
[46, 88, 81]]])
Подход № 2
Идя с вашей попытки, кажется, вы были достаточно близко. Мы могли бы получить к окончательному выводу несколько изменений / исправлений -
d1, d2, d3 = np.ogrid[:AB.shape[0], :AB.shape[1], :AB.shape[2]]
r[r < 0] += AB.shape[1]
D2 = ((d2 - r).transpose(2,1,0))%AB.shape[1]
out = AB[d1,D2,d3]