Shear a numpy array Shear a numpy array numpy numpy

Shear a numpy array


numpy roll does this. For example, if you original array is x then

for i in range(x.shape[1]):    x[:,i] = np.roll(x[:,i], i)

produces

[[11 36 19] [17 12 37] [35 18 13]]


This can be done using a trick described in this answer by Joe Kington:

from numpy.lib.stride_tricks import as_strideda = numpy.array([[11, 12, 13],                 [17, 18, 19],                 [35, 36, 37]])shift_axis = 0increase_axis = 1b = numpy.vstack((a, a))strides = list(b.strides)strides[increase_axis] -= strides[shift_axis]strides = (b.strides[0], b.strides[1] - b.strides[0])as_strided(b, shape=b.shape, strides=strides)[a.shape[0]:]# array([[11, 36, 19],#        [17, 12, 37],#        [35, 18, 13]])

To get "clip" instead of "roll", use

b = numpy.vstack((numpy.zeros(a.shape, int), a))

This is probably the most efficient way of doing it, since it does not use any Python loop at all.


The approach in tom10's answer can be extended to arbitrary dimensions:

def shear3(a, strength=1, shift_axis=0, increase_axis=1):    if shift_axis > increase_axis:        shift_axis -= 1    res = numpy.empty_like(a)    index = numpy.index_exp[:] * increase_axis    roll = numpy.roll    for i in range(0, a.shape[increase_axis]):        index_i = index + (i,)        res[index_i] = roll(a[index_i], -i * strength, shift_axis)    return res