python numpy slice

python - Seleccionando mĂșltiples cortes de una matriz numpy a la vez



slice (6)

Estoy buscando una manera de seleccionar múltiples rebanadas de una matriz numpy a la vez. Digamos que tenemos una matriz de datos 1D y queremos extraer tres porciones de ella como a continuación:

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

Posteriormente data_extractions será:

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

¿Hay alguna forma de realizar la operación anterior sin el bucle for? ¿Algún tipo de esquema de indexación en numpy que me permita seleccionar múltiples cortes de una matriz y devolverlos como esa cantidad de matrices, digamos en una matriz dimensional n + 1?

Pensé que tal vez podría replicar mis datos y luego seleccionar un intervalo de cada fila, pero el siguiente código arroja un IndexError

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


En el caso general, debe realizar algún tipo de iteración, y concatenación, ya sea al construir los índices o al recopilar los resultados. Solo cuando el patrón de corte es regular en sí mismo, puede usar un corte generalizado a través de as_strided .

La respuesta aceptada construye una matriz de indexación, una fila por segmento. Entonces eso es iterar sobre los sectores, y un arange sí mismo es una iteración (rápida). Y np.array concatena en un nuevo eje ( np.stack generaliza esto).

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 conveniencia indexing_tricks para hacer lo mismo:

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])

Esto toma la notación de corte, la expande con un arange y concatena. Incluso me permite ampliar y concatenar en 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'')

Los resultados de concatenación después de la indexación también funcionan.

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

Mi memoria de otras preguntas SO es que los tiempos relativos están en el mismo orden de magnitud. Puede variar, por ejemplo, con el número de cortes en función de su longitud. En general, el número de valores que deben copiarse de origen a destino será el mismo.

Si las secciones varían en longitud, tendrías que usar la indexación plana.


En esta publicación hay un enfoque con strided-indexing scheme np.lib.stride_tricks.as_strided que usa np.lib.stride_tricks.as_strided que básicamente crea una vista en la matriz de entrada y, como tal, es bastante eficiente para la creación y la vista ocupa un espacio de memoria similar. Además, esto funciona para ndarrays con un número genérico de dimensiones.

Aquí está la implementación:

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)

Ejecución de muestra para un 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


Podemos usar la comprensión de la lista para esto

data=np.array([1,2,3,4,5,6,7,8,9,10]) data_extractions=[data[b:b+5] for b in [1,2,3,4,5]] data_extractions

Resultados

[array([2, 3, 4, 5, 6]), array([3, 4, 5, 6, 7]), array([4, 5, 6, 7, 8]), array([5, 6, 7, 8, 9]), array([ 6, 7, 8, 9, 10])]


Puede cortar su matriz con una matriz de corte 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]

Sin embargo, b no tiene que generarse a mano de esta manera. Puede ser más dinámico con

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


Puede usar los índices para seleccionar las filas que desee en la forma adecuada. Por ejemplo:

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


stride_tricks puede hacer eso

a = np.arange(10) b = np.lib.stride_tricks.as_strided(a, (3, 5), 2 * a.strides) b # array([[0, 1, 2, 3, 4], # [1, 2, 3, 4, 5], # [2, 3, 4, 5, 6]])

Tenga en cuenta que b referencia a la misma memoria que a , de hecho varias veces (por ejemplo, b[0, 1] b[1, 0] son la misma dirección de memoria). Por lo tanto, es más seguro hacer una copia antes de trabajar con la nueva estructura.

nd se puede hacer de manera similar, por ejemplo 2d -> 4d

a = np.arange(16).reshape(4, 4) b = np.lib.stride_tricks.as_strided(a, (3,3,2,2), 2*a.strides) b.reshape(9,2,2) # this forces a copy # array([[[ 0, 1], # [ 4, 5]], # [[ 1, 2], # [ 5, 6]], # [[ 2, 3], # [ 6, 7]], # [[ 4, 5], # [ 8, 9]], # [[ 5, 6], # [ 9, 10]], # [[ 6, 7], # [10, 11]], # [[ 8, 9], # [12, 13]], # [[ 9, 10], # [13, 14]], # [[10, 11], # [14, 15]]])