Shear a numpy array

后端 未结 5 1664
执念已碎
执念已碎 2020-12-18 00:40

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

相关标签:
5条回答
  • 2020-12-18 01:13

    Here is a cleaned-up version of your own approach:

    def shear2(a, strength=1, shift_axis=0, increase_axis=1, edges='clip'):
        indices = numpy.indices(a.shape)
        indices[shift_axis] -= strength * indices[increase_axis]
        indices[shift_axis] %= a.shape[shift_axis]
        res = a[tuple(indices)]
        if edges == 'clip':
            res[indices[shift_axis] < 0] = 0
            res[indices[shift_axis] >= a.shape[shift_axis]] = 0
        return res
    

    The main difference is that it uses numpy.indices() instead of rolling your own version of this.

    0 讨论(0)
  • 2020-12-18 01:16

    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]]
    
    0 讨论(0)
  • 2020-12-18 01:17

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

    from numpy.lib.stride_tricks import as_strided
    a = numpy.array([[11, 12, 13],
                     [17, 18, 19],
                     [35, 36, 37]])
    shift_axis = 0
    increase_axis = 1
    b = 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.

    0 讨论(0)
  • 2020-12-18 01:20
    r = lambda l, n: l[n:]+l[:n]
    
    transpose(map(r, transpose(a), range(0, len(a)))
    

    I think. You should probably consider this psuedocode more than actual Python. Basically transpose the array, map a general rotate function over it to do the rotation, then transpose it back.

    0 讨论(0)
  • 2020-12-18 01:26

    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
    
    0 讨论(0)
提交回复
热议问题