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
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
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
On 9/24/06, Bill Baxter
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 multi-axis 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 re-insert in another). So perhaps the name should be
'moveaxis' instead?
--bb
On 9/25/06, Alan G Isaac
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