2012-02-17 9 views
11

Estoy tratando de usar el módulo itertools de Python para acelerar un ciclo triple anidado para. El código de prueba a continuación compara un bucle anidado de triple estándar con itertools' método del producto y salidas:Python itertools - lento?

anidadas tiempo de bucle = 2.35023 secs

itertools tiempo de bucle = 2.67766 segundos

Me estoy perdiendo algo?

import numpy 
import itertools 
import time 

n = 128 
a = numpy.arange(n**3).reshape((n,n,n)) 
b = numpy.zeros((n,n,n)) 
c = numpy.zeros((n,n,n)) 

t = time.time() 
for i in range(n): 
    for j in range(n): 
     for k in range(n): 
      b[i,j,k] = a[i,j,k] 
print 'Nested loop time = %g secs' % (time.time() - t) 

t = time.time() 
for (i,j,k) in itertools.product(range(n), repeat=3): 
    c[i,j,k] = a[i,j,k] 
print 'Itertools loop time = %g secs' % (time.time() - t) 
+0

"¿Me estoy perdiendo algo?" - Lo que parece que se está perdiendo es que nadie afirmó que la idea de 'itertools.product()' es acelerar los bucles anidados- –

+3

@Sven Marnach 9.7. itertools - Funciones que crean iteradores para un bucle eficiente ... http: //docs.python.org/library/itertools.html –

Respuesta

9

Parece como itertools.product es más lenta para valores grandes de n:

 
In [24]: print _23 
from itertools import product 

def nested_loops(n): 
    for i in range(n): 
     for j in range(n): 
      for k in range(n): 
       pass 

def itertools_product(n): 
    for (i,j,k) in product(range(n), repeat=3): 
     pass 


In [25]: %timeit nested_loops(128) 
10 loops, best of 3: 68.6 ms per loop 

In [26]: %timeit itertools_product(128) 
10 loops, best of 3: 162 ms per loop 

In [27]: %timeit nested_loops(10) 
10000 loops, best of 3: 84.5 us per loop 

In [28]: %timeit itertools_product(10) 
10000 loops, best of 3: 79.8 us per loop 

In [30]: %timeit nested_loops(300) 
1 loops, best of 3: 833 ms per loop 

In [31]: %timeit itertools_product(300) 
1 loops, best of 3: 2.07 s per loop 

y sin el desembalaje tupla:

 
In [40]: print _39 
from itertools import product 

def itertools_product(n): 
    for ijk in product(range(n), repeat=3): 
     pass 

In [41]: %timeit itertools_product(128) 
10 loops, best of 3: 115 ms per loop 

In [42]: %timeit itertools_product(10) 
10000 loops, best of 3: 59.2 us per loop 

In [43]: %timeit itertools_product(300) 
1 loops, best of 3: 1.47 s per loop 

Además, para la diversión, las listas por comprensión y expresiones generadoras :

 
def list_comprehension_product(n): 
    range_n = range(n) 
    for (i,j,k) in [ (i, j, k) for i in range_n for j in range_n for k in range_n ]: 
     pass 

def generator_expression_product(n): 
    range_n = range(n) 
    for (i,j,k) in ((i, j, k) for i in range_n for j in range_n for k in range_n): 
     pass 

In [51]: %timeit list_comprehension_product(128) 
1 loops, best of 3: 583 ms per loop 

In [52]: %timeit generator_expression_product(128) 
1 loops, best of 3: 480 ms per loop 

Estos puntos de referencia se realizaron con python --version:

2.6.7 (r267:88850, Jul 31 2011, 19:30:54) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
+1

Sí, parece ser más lento para rangos grandes. Y ahí es exactamente donde quieres que sea más rápido, ¿no? – repoman

5

Parece que el segundo bucle es más lento que el primero, tal vez por el desempaquetado de tuplas. Usted no tiene que hacer eso, y me parece que hace que el segundo bucle más rápido que hacerlo de esta manera:

for ijk in itertools.product(range(n), repeat=3): 
    c[ijk] = a[ijk] 

Por supuesto, con numpy, se quiere evitar un bucle sobre los elementos en absoluto, y en lugar de utilizar operaciones numpy en toda la matriz a la vez. De esa forma, todo el looping, etc., se está haciendo en C, y obtendrás aceleraciones enormes.

+0

No quería que esto estuviera relacionado con el numpy. Acabo de usar numpy para tener algo que permita una rápida indexación triple. Podría haber sido una llamada a alguna función con un triple argumento ... – repoman

Cuestiones relacionadas