матрица: эффективное перемещение n-й строки на n позиций - PullRequest
1 голос
/ 04 ноября 2019

У меня есть массивный двумерный массив, и мне нужно преобразовать его таким образом, чтобы первый ряд остался прежним, второй ряд переместился на одну позицию вправо (он может обернуться вокруг или просто иметь ноль, добавленный вперед),Третий ряд сдвигает 3 позиции вправо и т. Д. Я могу сделать это через цикл «for», но это не очень эффективно. Я предполагаю, что должна быть фильтрующая матрица, умноженная на исходную, будет иметь такой же эффект, или, может быть, полезный трюк, который поможет мне сделать это? Спасибо! Я изучил numpy.roll (), но не думаю, что он может работать с каждой строкой отдельно.

import numpy as np
p = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
'''
p = [ 1   2   3   4
      5   6   7   8
      9   10  11  12
      13  14  15  16]
desired output:
p'= [ 1   2   3   4
      0   5   6   7
      0   0   9   10
      0   0   0   13]
'''

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

Мы можем извлечь скользящие окна в заполненную нулями версию ввода, чтобы иметь эффективный подход к памяти и, следовательно, производительность. Чтобы получить эти окна, мы можем использовать np.lib.stride_tricks.as_strided на основе scikit-image's view_as_windows. Более подробная информация об использовании as_strided на основе view_as_windows.

Следовательно, решение будет -

from skimage.util.shape import view_as_windows

def slide_by_one(p):
    m,n = p.shape
    z = np.zeros((m,m-1),dtype=p.dtype)
    a = np.concatenate((z,p),axis=1)
    w  = view_as_windows(a,(1,p.shape[1]))[...,0,:]
    r = np.arange(m)
    return w[r,r[::-1]]

Пример выполнения -

In [60]: p # generic sample of size mxn
Out[60]: 
array([[ 1,  5,  9, 13, 17],
       [ 2,  6, 10, 14, 18],
       [ 3,  7, 11, 15, 19],
       [ 4,  8, 12, 16, 20]])

In [61]: slide_by_one(p)
Out[61]: 
array([[ 1,  5,  9, 13, 17],
       [ 0,  2,  6, 10, 14],
       [ 0,  0,  3,  7, 11],
       [ 0,  0,  0,  4,  8]])

Мы можем использовать обычный шаблон rampy , чтобы иметь более эффективный подход с более грубым использованием np.lib.stride_tricks.as_strided, например, -

def slide_by_one_v2(p):
    m,n = p.shape
    z = np.zeros((m,m-1),dtype=p.dtype)
    a = np.concatenate((z,p),axis=1)
    s0,s1 = a.strides
    return np.lib.stride_tricks.as_strided(a[:,m-1:],shape=(m,n),strides=(s0-s1,s1))

Еще один с некоторыми masking -

def slide_by_one_v3(p):
    m,n = p.shape
    z = np.zeros((len(p),1),dtype=p.dtype)
    a = np.concatenate((p,z),axis=1)
    return np.triu(a[:,::-1],1)[:,::-1].flat[:-m].reshape(m,-1)
1 голос
/ 04 ноября 2019

Вот простой метод, основанный на заполнении нулями и изменении формы. Это быстро, потому что избегает расширенной индексации и других издержек.

def pp(p):
    m,n = p.shape
    aux = np.zeros((m,n+m-1),p.dtype)
    np.copyto(aux[:,:n],p)
    return aux.ravel()[:-m].reshape(m,n+m-2)[:,:n].copy()
...