python - array - Selecionando várias fatias de uma matriz numpy de uma só vez




reshape list python (4)

Nesta publicação, há uma abordagem com strided-indexing scheme np.lib.stride_tricks.as_strided usando np.lib.stride_tricks.as_strided que basicamente cria uma visualização na matriz de entrada e, como tal, é bastante eficiente para criação e, sendo assim, a visualização ocupa espaço de memória nomore. Além disso, isso funciona para ndarrays com número genérico de dimensões.

Aqui está a implementação -

def strided_axis0(a, L):
    # Store the shape and strides info
    shp = a.shape
    s  = a.strides

    # Compute length of output array along the first axis
    nd0 = shp[0]-L+1

    # Setup shape and strides for use with np.lib.stride_tricks.as_strided
    # and get (n+1) dim output array
    shp_in = (nd0,L)+shp[1:]
    strd_in = (s[0],) + s
    return np.lib.stride_tricks.as_strided(a, shape=shp_in, strides=strd_in)

Exemplo de execução para um caso de matriz 4D -

In [44]: a = np.random.randint(11,99,(10,4,2,3)) # Array

In [45]: L = 5      # Window length along the first axis

In [46]: out = strided_axis0(a, L)

In [47]: np.allclose(a[0:L], out[0])  # Verify outputs
Out[47]: True

In [48]: np.allclose(a[1:L+1], out[1])
Out[48]: True

In [49]: np.allclose(a[2:L+2], out[2])
Out[49]: True

Estou procurando uma maneira de selecionar várias fatias de uma matriz numpy de uma só vez. Digamos que temos uma matriz de dados 1D e queremos extrair três partes, como abaixo:

data_extractions = []

for start_index in range(0, 3):
    data_extractions.append(data[start_index: start_index + 5])

Depois, as data_extractions serão:

data_extractions = [
    data[0:5],
    data[1:6],
    data[2:7]
]

Existe alguma maneira de executar a operação acima sem o loop for? Algum tipo de esquema de indexação numpy que me permitia selecionar várias fatias de uma matriz e devolvê-las como muitas matrizes, digamos em uma matriz dimensional n + 1?

Eu pensei que talvez eu possa replicar meus dados e selecione um intervalo de cada linha, mas o código abaixo gera um IndexError

replicated_data = np.vstack([data] * 3)
data_extractions = replicated_data[[range(3)], [slice(0, 5), slice(1, 6), slice(2, 7)]

No caso geral, você precisa fazer algum tipo de iteração - e concatenação - ao construir os índices ou ao coletar os resultados. Somente quando o padrão de fatia é regular, é possível usar uma fatia generalizada via as_strided .

A resposta aceita constrói uma matriz de indexação, uma linha por fatia. Portanto, ele está iterando sobre as fatias e a própria arange é uma iteração (rápida). E o np.array concatena em um novo eixo (o np.stack generaliza isso).

In [264]: np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
Out[264]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

métodos de conveniência indexing_tricks para fazer a mesma coisa:

In [265]: np.r_[0:5, 1:6, 2:7]
Out[265]: array([0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6])

Isso pega a notação de fatia, a expande com arange e concatena. Até me permite expandir e concatenar em 2D

In [269]: np.r_['0,2',0:5, 1:6, 2:7]
Out[269]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

In [270]: data=np.array(list('abcdefghijk'))
In [272]: data[np.r_['0,2',0:5, 1:6, 2:7]]
Out[272]: 
array([['a', 'b', 'c', 'd', 'e'],
       ['b', 'c', 'd', 'e', 'f'],
       ['c', 'd', 'e', 'f', 'g']], 
      dtype='<U1')
In [273]: data[np.r_[0:5, 1:6, 2:7]]
Out[273]: 
array(['a', 'b', 'c', 'd', 'e', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e',
       'f', 'g'], 
      dtype='<U1')

Concatenar resultados após a indexação também funciona.

In [274]: np.stack([data[0:5],data[1:6],data[2:7]])

Minha memória de outras questões de SO é que os tempos relativos estão na mesma ordem de magnitude. Pode variar, por exemplo, com o número de fatias versus seu comprimento. No geral, o número de valores que precisam ser copiados da origem para o destino será o mesmo.

Se as fatias variarem em comprimento, você precisará usar a indexação plana.


Você pode fatiar sua matriz com uma matriz de fatias preparada

a = np.array(list('abcdefg'))

b = np.array([
        [0, 1, 2, 3, 4],
        [1, 2, 3, 4, 5],
        [2, 3, 4, 5, 6]
    ])

a[b]

No entanto, b não precisa ser gerado manualmente dessa maneira. Pode ser mais dinâmico com

b = np.arange(5) + np.arange(3)[:, None]

Você pode usar os índices para selecionar as linhas que deseja na forma apropriada. Por exemplo:

 data = np.random.normal(size=(100,2,2,2))

 # Creating an array of row-indexes
 indexes = np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
 # data[indexes] will return an element of shape (3,5,2,2,2). Converting
 # to list happens along axis 0
 data_extractions = list(data[indexes])

 np.all(data_extractions[1] == s[1:6])
 True




slice