Hi all, Other data languages that I have worked with have a routine for shifting data along axes, with wrapping. In IDL it's called 'shift', and works such that print, a 0 1 2 3 4 5 6 7 8 9 10 11 print, shift(a, 2, 0) 2 3 0 1 6 7 4 5 10 11 8 9 print, shift(a, 2, 1) 10 11 8 9 2 3 0 1 6 7 4 5 In pdl (pdl.perl.org) the equivalent routine is called rotate. Is there a version of this in numpy, or can it be easily achieved using existing technology  I could do it with multiple sliced assignment statements but that seems very clunky and likely slow. I've looked through the examples and the numpy book but without success. Angus.  AJC McMorland, PhD Student Physiology, University of Auckland Armourer, Auckland University Fencing Secretary, Fencing North Inc.
Howdy Angus, Yeh, that does seem like a hole in the API. Travis added a rollaxis() but there's still no simple way to roll the elements themselves. I took a look at numpy.fft.fftshift, which is a function that has to do a similar thing. It does it by concatenating aranges and then doing a take(). Presumably Pearu knew what he was doing when he wrote that, so we can assume this is probably close to the best possible. :) From that idea here's a function that implements roll(). def roll(y,shift,axis): """Roll the elements in the array by 'shift' positions along the given axis.""" from numpy import asanyarray,concatenate,arange y = asanyarray(y) n = y.shape[axis] shift %= n # does the right thing for negative shifts, too return y.take(concatenate((arange(shift,n),arange(shift))), axis) Performance is only very slightly worse (<1%) using return y.take(r_[shift:n, :shift], axis) as the last line, which is maybe slightly more readable if you're down wit' the r_. I prefer the name 'roll' because: a) there's already rollaxis with conceptually similar behavior and b) 'shift' is used in other languages (perl comes to mind) sometimes to indicate shifting off the end, possibly filling in with zeros or just leaving the array shorter. c) 'rotate' seems potentially confusing given the existence of the 'rot90' function already. bb On 9/25/06, Angus McMorland <amcmorl@gmail.com> wrote:
Hi all,
Other data languages that I have worked with have a routine for shifting data along axes, with wrapping. In IDL it's called 'shift', and works such that print, a 0 1 2 3 4 5 6 7 8 9 10 11
print, shift(a, 2, 0) 2 3 0 1 6 7 4 5 10 11 8 9
print, shift(a, 2, 1) 10 11 8 9 2 3 0 1 6 7 4 5
In pdl (pdl.perl.org) the equivalent routine is called rotate. Is there a version of this in numpy, or can it be easily achieved using existing technology  I could do it with multiple sliced assignment statements but that seems very clunky and likely slow. I've looked through the examples and the numpy book but without success.
Angus.
On 9/24/06, Bill Baxter <wbaxter@gmail.com> wrote:
Howdy Angus, Yeh, that does seem like a hole in the API. Travis added a rollaxis() but there's still no simple way to roll the elements themselves.
I took a look at numpy.fft.fftshift, which is a function that has to do a similar thing. It does it by concatenating aranges and then doing a take(). Presumably Pearu knew what he was doing when he wrote that, so we can assume this is probably close to the best possible. :) From that idea here's a function that implements roll().
def roll(y,shift,axis): """Roll the elements in the array by 'shift' positions along the given axis.""" from numpy import asanyarray,concatenate,arange y = asanyarray(y) n = y.shape[axis] shift %= n # does the right thing for negative shifts, too return y.take(concatenate((arange(shift,n),arange(shift))), axis)
It is possible to do a shift inplace using two reflections implemented with swaps. This works because two reflections is the same as a rotating twice the distance between the centers of the reflections. I don't know if it is worth implementing this, however. Chuck
Went ahead and added an enhancement request: http://projects.scipy.org/scipy/numpy/ticket/293 This is something I've wanted in the past too. bb On 9/25/06, Charles R Harris <charlesr.harris@gmail.com> wrote:
On 9/24/06, Bill Baxter <wbaxter@gmail.com> wrote:
Howdy Angus, Yeh, that does seem like a hole in the API. Travis added a rollaxis() but there's still no simple way to roll the elements themselves.
I took a look at numpy.fft.fftshift, which is a function that has to do a similar thing. It does it by concatenating aranges and then doing a take(). Presumably Pearu knew what he was doing when he wrote that, so we can assume this is probably close to the best possible. :) From that idea here's a function that implements roll().
def roll(y,shift,axis): """Roll the elements in the array by 'shift' positions along the given axis.""" from numpy import asanyarray,concatenate,arange y = asanyarray(y) n = y.shape[axis] shift %= n # does the right thing for negative shifts, too return y.take(concatenate((arange(shift,n),arange(shift))), axis)
It is possible to do a shift inplace using two reflections implemented with swaps. This works because two reflections is the same as a rotating twice the distance between the centers of the reflections. I don't know if it is worth implementing this, however.
Chuck
On Mon, 25 Sep 2006, Bill Baxter apparently wrote:
Went ahead and added an enhancement request: http://projects.scipy.org/scipy/numpy/ticket/293 This is something I've wanted in the past too.
GAUSS draws a useful distinction between "shifting" and "rotating": Works roughly like this for the 2D case: #rotater: rotate row elements # Format: y = rotater(x,r) # rotater(x,r) # Input: x RxK array # rotateby size R integer array, or integer (rotation amounts) # Output: y RxK array: # rows rotated by rotateby #shiftr: shift row elements and fill with fv # Format: y = shiftr(x,shiftby,fv) # Input: x RxC array # shiftby Rx1 array or scalar (shift amounts) # fv Rx1 array or scalar (fill values) # Output: y RxC array: # rows shifted by shiftby # rows filled with fill fwiw, Alan Isaac
Hmm. Yes maybe a shift w/fill would be useful too. I can't recall needing such a thing, but it could probably also be implemented easily in a way similar to roll() above. A multiaxis roll might also be nice. Could just allow roll's shiftby and axis args to be tuples. Looking closer at the existing 'rollaxis', numpy.rollaxis(a, axis, start=0) if a.shape is (3,4,5,6) rollaxis(a, 3, 1).shape is (3,6,4,5) rollaxis(a, 2, 0).shape is (5,3,4,6) rollaxis(a, 1, 3).shape is (3,5,4,6) rollaxis(a, 1, 4).shape is (3,5,6,4) it occurs to me that what it is actually doing is not what we've been calling 'rolling'. It's just a move, really (remove value from one place and reinsert in another). So perhaps the name should be 'moveaxis' instead? bb On 9/25/06, Alan G Isaac <aisaac@american.edu> wrote:
On Mon, 25 Sep 2006, Bill Baxter apparently wrote:
Went ahead and added an enhancement request: http://projects.scipy.org/scipy/numpy/ticket/293 This is something I've wanted in the past too.
GAUSS draws a useful distinction between "shifting" and "rotating":
Works roughly like this for the 2D case:
#rotater: rotate row elements # Format: y = rotater(x,r) # rotater(x,r) # Input: x RxK array # rotateby size R integer array, or integer (rotation amounts) # Output: y RxK array: # rows rotated by rotateby
#shiftr: shift row elements and fill with fv # Format: y = shiftr(x,shiftby,fv) # Input: x RxC array # shiftby Rx1 array or scalar (shift amounts) # fv Rx1 array or scalar (fill values) # Output: y RxC array: # rows shifted by shiftby # rows filled with fill
fwiw, Alan Isaac
participants (4)

Alan G Isaac

Angus McMorland

Bill Baxter

Charles R Harris