Pregunta ¿cuál es la forma más rápida de iterar a través de una matriz numpy


Noté una diferencia significativa entre iterar a través de una matriz numpy "directamente" versus iterar a través de la tolist método. Vea el tiempo a continuación:

directamente
[i for i in np.arange(10000000)]
vía tolist
[i for i in np.arange(10000000).tolist()] 

enter image description here


teniendo en cuenta que he descubierto una forma de ir más rápido. Quería preguntar qué más podría hacerlo ir más rápido.

¿Cuál es la forma más rápida de iterar a través de una matriz numpy? 


7
2017-11-14 16:28


origen


Respuestas:


Estos son mis tiempos en una máquina más lenta

In [1034]: timeit [i for i in np.arange(10000000)]
1 loop, best of 3: 2.16 s per loop

Si genero el rango directamente (Py3 entonces esto es un genertor) los tiempos son mucho mejores. Toma esto como una línea de base para una comprensión de la lista de este tamaño.

In [1035]: timeit [i for i in range(10000000)]
1 loop, best of 3: 1.26 s per loop

tolist convierte el arange en una lista primero; toma un poco más de tiempo, pero la iteración todavía está en una lista

In [1036]: timeit [i for i in np.arange(10000000).tolist()]
1 loop, best of 3: 1.6 s per loop

Utilizando list() - al mismo tiempo que la iteración directa en la matriz; eso sugiere que la iteración directa primero hace esto.

In [1037]: timeit [i for i in list(np.arange(10000000))]
1 loop, best of 3: 2.18 s per loop

In [1038]: timeit np.arange(10000000).tolist()
1 loop, best of 3: 927 ms per loop

las mismas veces una iteración en el .tolist

In [1039]: timeit list(np.arange(10000000))
1 loop, best of 3: 1.55 s per loop

En general, si debe realizar un bucle, trabajar en una lista es más rápido. El acceso a los elementos de una lista es más simple.

Mira los elementos devueltos por la indexación.

a[0] es otro numpy objeto; está construido a partir de los valores en a, pero no simplemente un valor obtenido

list(a)[0] es del mismo tipo; la lista es solo [a[0], a[1], a[2]]]

In [1043]: a = np.arange(3)
In [1044]: type(a[0])
Out[1044]: numpy.int32
In [1045]: ll=list(a)
In [1046]: type(ll[0])
Out[1046]: numpy.int32

pero tolist convierte la matriz en una lista pura, en este caso, como una lista de ints. Hace más trabajo que list(), pero lo hace en código compilado.

In [1047]: ll=a.tolist()
In [1048]: type(ll[0])
Out[1048]: int

En general, no uses list(anarray). Raramente hace algo útil, y no es tan poderoso como tolist().

¿Cuál es la forma más rápida de iterar a través de la matriz? Ninguno. Al menos no en Python; en el código c hay formas rápidas.

a.tolist() es la forma más rápida y vectorizada de crear una lista de enteros a partir de una matriz. Se itera, pero lo hace en código compilado.

Pero, ¿cuál es tu verdadero objetivo?


5
2017-11-14 16:55



Esto en realidad no es sorprendente. Examinemos los métodos uno por vez comenzando por el más lento.

[i for i in np.arange(10000000)]

Este método le pide a python que alcance la matriz numpy (almacenada en el alcance de la memoria C), un elemento a la vez, asigne un objeto Python en la memoria y cree un puntero a ese objeto en la lista. Cada vez que canaliza entre la matriz numpy almacenada en el backend de C y la convierte en python puro, hay un costo general. Este método agrega un costo de 10,000,000 de veces.

Siguiente:

[i for i in np.arange(10000000).tolist()]

En este caso, usando .tolist() realiza una única llamada al backend numpy C y asigna todos los elementos de una sola vez a una lista. Entonces estás usando python para iterar sobre esa lista.

Finalmente:

list(np.arange(10000000))

Esto básicamente hace lo mismo que arriba, pero crea una lista de objetos de tipo nativo de Numpy (p. np.int64) Utilizando list(np.arange(10000000)) y np.arange(10000000).tolist() debería ser más o menos al mismo tiempo.


Entonces, en términos de iteración, la principal ventaja de usar numpy es que no necesitas iterar. La operación se aplica de forma vectorializada sobre la matriz. La iteración solo lo ralentiza. Si te encuentras iterando sobre los elementos de la matriz, deberías buscar la manera de reestructurar el algoritmo que estás intentando, de tal forma que solo se usen operaciones numpy (¡tiene tantas incorporadas!) O si es realmente necesario, puedes utilizar np.apply_along_axis, np.apply_over_axis, o np.vectorize.


8
2017-11-14 16:48



Mi caso de prueba tiene un numpy array 

[[  34  107]
 [ 963  144]
 [ 921 1187]
 [   0 1149]]

Estoy pasando por esto solo una vez usando range y enumerate

Rango de uso

loopTimer1 = default_timer()
for l1 in range(0,4):
    print(box[l1])
print("Time taken by range: ",default_timer()-loopTimer1)

Resultado

[ 34 107]
[963 144]
[ 921 1187]
[   0 1149]
Time taken by range:  0.0005405639985838206

UTILIZANDO enumerar

loopTimer2 = default_timer()
for l2,v2 in enumerate(box):
    print(box[l2])
print("Time taken by enumerate: ", default_timer() - loopTimer2)

Resultado

[ 34 107]
[963 144]
[ 921 1187]
[   0 1149]
Time taken by enumerate:  0.00025605700102460105

Este caso de prueba que escogí enumerate funcionará más rápido


0
2018-05-15 07:55



Preguntas populares