2011-01-27 26 views
15

Estoy realmente confundido por la lógica de índice de las matrices numpy con varias dimensiones. Aquí está un ejemplo:Confusión de índice en matrices numpy

import numpy as np 
A = np.arange(18).reshape(3,2,3) 
[[[ 0, 1, 2], 
    [ 3, 4, 5]], 

[[ 6, 7, 8], 
    [ 9, 10, 11]], 

[[12, 13, 14], 
    [15, 16, 17]]]) 

esto me da una matriz de forma (3,2,3), llamar a ellos (x, y, z) para bien del argumento. Ahora quiero una matriz B con los elementos de A correspondientes a x = 0,2 y = 0,1 yz = 1,2. Al igual que

array([[[ 1, 2], 
     [4, 5]], 

     [[13, 14], 
     [16, 17]]]) 

Ingenuamente pensé que

B=A[[0,2],[0,1],[1,2]] 

haría el trabajo. Pero da

array([ 2, 104]) 

y no funciona.

A[[0,2],:,:][:,:,[1,2]] 

hace el trabajo. Pero todavía me pregunto qué pasa con mi primer intento. ¿Y cuál es la mejor manera de hacer lo que quiero hacer?

+0

Mi opinión personal: ambas formas activan la indexación avanzada de Numpy. En el contexto de indexación avanzada, A [[0,2], [0,1], [1,2]] se interpreta como "seleccionado cada número de indexación en cada una de sus dimensiones (un enfoque un tanto codicioso). –

Respuesta

17

Hay dos tipos de indexación en NumPy basic y advanced. La indexación básica usa tuplas de sectores para indexar, y no copia la matriz, sino creates a view with adjusted strides. La indexación avanzada, por el contrario, también usa listas o matrices de índices y copia la matriz.

Su primer intento

B = A[[0, 2], [0, 1], [1, 2]] 

utiliza la indexación avanzada. En la indexación avanzada, todas las listas de índices son primero broadcasted con la misma forma, y ​​esta forma se usa para la matriz de salida. En este caso, ya tienen la misma forma, por lo que la transmisión no hace nada. La matriz de salida también tendrá esta forma de dos entradas.La primera entrada de la matriz de salida se obtiene mediante el uso de todos los primeros índices de las tres listas, y la segunda mediante el uso de todos los segundos índices:

B = numpy.array([A[0, 0, 1], A[2, 1, 2]]) 

Su segundo enfoque

B = A[[0,2],:,:][:,:,[1,2]] 

funciona, pero es ineficiente Utiliza indexación avanzada dos veces, por lo que sus datos se copiarán dos veces.

para conseguir lo que realmente desea con la indexación avanzada, puede utilizar

A[np.ix_([0,2],[0,1],[1,2])] 

como señala nikow. Esto copiará los datos solo una vez.

En su ejemplo, se puede salir sin copiar los datos en absoluto, utilizando sólo la indexación básica:

B = A[::2, :, 1:2] 
+0

Gracias Sven, pero ¿hay una mejor manera de extraer índices que no son contius (o espaciados regularmente) de una matriz, que utilizando indexación avanzada. (Mi ejemplo era demasiado simple, como todo los índices que extraigo están continuamente espaciados) – jonalm

+0

Si sus índices no están regularmente espaciados, por supuesto tendrá que usar indexación avanzada. El camino a seguir en este caso es la sintaxis 'ix_', como ya lo señaló nikow. solo quería agregar más detalles, como que n enfoque es ineficiente para grandes matrices. –

+0

Excelente respuesta, y gracias por señalar mis errores. Debería haber pensado en las implicaciones de eficiencia de la indexación avanzada. – nikow

7

recomiendo el siguiente tutorial avanzado, lo que explica los diversos métodos de indexación: NumPy MedKit

Una vez que entienda las maneras de gran alcance para las matrices de índice (y la forma en que se pueden combinar) tendrá sentido. Si su primer intento fue válido, esto colisionaría con algunas de las otras técnicas de indexación (reduciendo sus opciones en otros casos de uso).

En su ejemplo se puede explotar de que el tercer índice cubre un rango continuo:

A[[0,2],:,1:] 

También es posible usar

A[np.ix_([0,2],[0,1],[1,2])] 

que es muy útil en los casos más generales, cuando los últimos índices se no continuo np.ix_ simplemente construye tres matrices de índice.

Como Sven señaló en su respuesta, hay una manera más eficiente en este caso específico (utilizando una vista en lugar de una versión copiada).

Edit: Como lo señaló Sven, mi respuesta contenía algunos errores, que he eliminado. Sigo pensando que su respuesta es mejor, pero desafortunadamente no puedo eliminar la mía ahora.

+0

Algunas observaciones: 1 Los primeros dos fragmentos de código no son equivalentes, producen matrices de diferentes formas. La primera línea es ** no ** interpretada como la segunda 2. La solución de jonalm no es aconsejable ya que copia la matriz dos veces. para explicar estos problemas un poco más en otra respuesta. –

0
A[(0,2),:,1:] 

Si quería

array([[[ 1, 2], 
     [ 4, 5]], 

     [[13, 14], 
     [16, 17]]]) 

A [índices que desea, filas que desee, col que desee]

Cuestiones relacionadas