9
I'd like to 'shear' a numpy array. I'm not sure I'm using the term 'shear' correctly; by shear, I mean something like:
Shift the first column by 0 places
Shift the second column by 1 place
Shift the third colum by 2 places
etc...
So this array:
array([[11, 12, 13],
[17, 18, 19],
[35, 36, 37]])
would turn into either this array:
array([[11, 36, 19],
[17, 12, 37],
[35, 18, 13]])
or something like this array:
array([[11, 0, 0],
[17, 12, 0],
[35, 18, 13]])
depending on how we handle the edges. I'm not too particular about edge behavior.
Here's my attempt at a function that does this:
import numpy
def shear(a, strength=1, shift_axis=0, increase_axis=1, edges='clip'):
strength = int(strength)
shift_axis = int(shift_axis)
increase_axis = int(increase_axis)
if shift_axis == increase_axis:
raise UserWarning("Shear can't shift in the direction it increases")
temp = numpy.zeros(a.shape, dtype=int)
indices = []
for d, num in enumerate(a.shape):
coords = numpy.arange(num)
shape = [1] * len(a.shape)
shape[d] = num
coords = coords.reshape(shape) + temp
indices.append(coords)
indices[shift_axis] -= strength * indices[increase_axis]
if edges == 'clip':
indices[shift_axis][indices[shift_axis] < 0] = -1
indices[shift_axis][indices[shift_axis] >= a.shape[shift_axis]] = -1
res = a[indices]
res[indices[shift_axis] == -1] = 0
elif edges == 'roll':
indices[shift_axis] %= a.shape[shift_axis]
res = a[indices]
return res
if __name__ == '__main__':
a = numpy.random.random((3,4))
print a
print shear(a)
It seems to work. Please tell me if it doesn't!
It also seems clunky and inelegant. Am I overlooking a builtin nu