Theoretically, using scipy.ndimage.interpolation.shift described by @Ed Smith should work, but due to an open error ( https://github.com/scipy/scipy/issues/1323 ), it does not produce a result equivalent to several calls np.roll .
UPDATE: "Multi-roll" was added to numpy.roll in numpy version 1.12.0. Here is a two-dimensional example in which the first axis is rolled in one position, and the second axis is rolled in three positions:
In [7]: x = np.arange(20).reshape(4,5) In [8]: x Out[8]: array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) In [9]: numpy.roll(x, [1, 3], axis=(0, 1)) Out[9]: array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]])
This makes the code below obsolete. I will leave it there for posterity.
The code below defines a function that I call multiroll that does what you want. Here's an example in which it is applied to an array with the form (500, 500, 500):
In [64]: x = np.random.randn(500, 500, 500) In [65]: shift = [10, 15, 20]
Use multiple calls to np.roll to generate the expected result:
In [66]: yroll3 = np.roll(np.roll(np.roll(x, shift[0], axis=0), shift[1], axis=1), shift[2], axis=2)
Generate the shifted array with multiroll :
In [67]: ymulti = multiroll(x, shift)
Make sure we get the expected result:
In [68]: np.all(yroll3 == ymulti) Out[68]: True
For an array of this size, making three calls to np.roll is almost three times slower than calling multiroll :
In [69]: %timeit yroll3 = np.roll(np.roll(np.roll(x, shift[0], axis=0), shift[1], axis=1), shift[2], axis=2) 1 loops, best of 3: 1.34 s per loop In [70]: %timeit ymulti = multiroll(x, shift) 1 loops, best of 3: 474 ms per loop
Here is the definition of multiroll :
from itertools import product import numpy as np def multiroll(x, shift, axis=None): """Roll an array along each axis. Parameters ---------- x : array_like Array to be rolled. shift : sequence of int Number of indices by which to shift each axis. axis : sequence of int, optional The axes to be rolled. If not given, all axes is assumed, and len(shift) must equal the number of dimensions of x. Returns ------- y : numpy array, with the same type and size as x The rolled array. Notes ----- The length of x along each axis must be positive. The function does not handle arrays that have axes with length 0. See Also -------- numpy.roll Example ------- Here a two-dimensional array: >>> x = np.arange(20).reshape(4,5) >>> x array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) Roll the first axis one step and the second axis three steps: >>> multiroll(x, [1, 3]) array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]]) That equivalent to: >>> np.roll(np.roll(x, 1, axis=0), 3, axis=1) array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]]) Not all the axes must be rolled. The following uses the `axis` argument to roll just the second axis: >>> multiroll(x, [2], axis=[1]) array([[ 3, 4, 0, 1, 2], [ 8, 9, 5, 6, 7], [13, 14, 10, 11, 12], [18, 19, 15, 16, 17]]) which is equivalent to: >>> np.roll(x, 2, axis=1) array([[ 3, 4, 0, 1, 2], [ 8, 9, 5, 6, 7], [13, 14, 10, 11, 12], [18, 19, 15, 16, 17]]) """ x = np.asarray(x) if axis is None: if len(shift) != x.ndim: raise ValueError("The array has %d axes, but len(shift) is only " "%d. When 'axis' is not given, a shift must be " "provided for all axes." % (x.ndim, len(shift))) axis = range(x.ndim) else: