slicing array python numpy indexing slice

array - python numpy slice



Rápido numpy imaginación de lujo (3)

Mi código para cortar una matriz numpy (a través de la indexación elegante) es muy lento. Actualmente es un cuello de botella en el programa.

a.shape (3218, 6) ts = time.time(); a[rows][:, cols]; te = time.time(); print(''%.8f'' % (te-ts)); 0.00200009

¿Cuál es la llamada numpy correcta para obtener una matriz que consta del subconjunto de filas ''filas'' y columnas ''col'' de la matriz a? (de hecho, necesito la transposición de este resultado)


Para mi sorpresa, el tipo de expresión larga, que calcula los primeros índices 1D lineales, es más del 50% más rápida que la indexación consecutiva de matriz presentada en la pregunta:

(a.ravel()[( cols + (rows * a.shape[1]).reshape((-1,1)) ).ravel()]).reshape(rows.size, cols.size)

ACTUALIZACIÓN: OP actualizó la descripción de la forma de la matriz inicial. Con el tamaño actualizado, la aceleración está ahora por encima del 99% :

In [93]: a = np.random.randn(3218, 1415) In [94]: rows = np.random.randint(a.shape[0], size=2000) In [95]: cols = np.random.randint(a.shape[1], size=6) In [96]: timeit a[rows][:, cols] 10 loops, best of 3: 186 ms per loop In [97]: timeit (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size) 1000 loops, best of 3: 1.56 ms per loop

RESPUESTA INICIAL: Aquí está la transcripción:

In [79]: a = np.random.randn(3218, 6) In [80]: a.shape Out[80]: (3218, 6) In [81]: rows = np.random.randint(a.shape[0], size=2000) In [82]: cols = np.array([1,3,4,5])

Método de tiempo 1:

In [83]: timeit a[rows][:, cols] 1000 loops, best of 3: 1.26 ms per loop

Método de tiempo 2:

In [84]: timeit (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size) 1000 loops, best of 3: 568 us per loop

Verifique que los resultados sean los mismos:

In [85]: result1 = a[rows][:, cols] In [86]: result2 = (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size) In [87]: np.sum(result1 - result2) Out[87]: 0.0


Puede obtener un poco de velocidad si corta usando indización y transmisión sofisticadas:

from __future__ import division import numpy as np def slice_1(a, rs, cs) : return a[rs][:, cs] def slice_2(a, rs, cs) : return a[rs[:, None], cs] >>> rows, cols = 3218, 6 >>> rs = np.unique(np.random.randint(0, rows, size=(rows//2,))) >>> cs = np.unique(np.random.randint(0, cols, size=(cols//2,))) >>> a = np.random.rand(rows, cols) >>> import timeit >>> print timeit.timeit(''slice_1(a, rs, cs)'', ''from __main__ import slice_1, a, rs, cs'', number=1000) 0.24083110865 >>> print timeit.timeit(''slice_2(a, rs, cs)'', ''from __main__ import slice_2, a, rs, cs'', number=1000) 0.206566124519

Si piensas en términos de porcentajes, hacer algo 15% más rápido siempre es bueno, pero en mi sistema, para el tamaño de tu matriz, esto nos está restando 40 usd para hacer el corte, y es difícil creer que una operación 240 nosotros serán tu cuello de botella.


Permítanme tratar de resumir las excelentes respuestas de Jaime y TheodrosZelleke y mezclar en algunos comentarios.

  1. La indexación avanzada (de lujo) siempre devuelve una copia, nunca una vista.
  2. a[rows][:,cols] implica dos operaciones de indexación sofisticadas, por lo que se crea y descarta una copia intermedia a[rows] . Práctico y legible, pero no muy eficiente. Además, tenga en cuenta que [:,cols] generalmente genera una copia contigua de Fortran a partir de una C-cont. fuente.
  3. a[rows.reshape(-1,1),cols] es una única expresión de indexación avanzada que se basa en el hecho de que rows.reshape(-1,1) y cols se transmiten a la forma del resultado previsto.
  4. Una experiencia común es que la indexación en una matriz aplanada puede ser más eficiente que la indexación de lujo, por lo que otro enfoque es

    indx = rows.reshape(-1,1)*a.shape[1] + cols a.take(indx)

    o

    a.take(indx.flat).reshape(rows.size,cols.size)

  5. La eficiencia dependerá de los patrones de acceso a la memoria y de si la matriz inicial es C-contorneada o Fortran continua, por lo que se necesita experimentación.

  6. Utilice la indexación sofisticada solo si realmente lo necesita: el corte básico de a[rstart:rstop:rstep, cstart:cstop:cstep] devuelve una vista (aunque no continua) y debe ser más rápido.