¿Por qué estás optimizando esto? ¿Ha escrito un código de trabajo probado, luego examinó su algoritmo profiled y descubrió que optimizarlo tendrá un efecto? ¿Estás haciendo esto en un profundo bucle interno donde descubres que estás gastando tu tiempo? Si no, no te molestes.
Solo sabrá cuál funciona más rápido para usted al cronometrarlo. Para cronometrarlo de manera útil, deberá especializarlo en su caso de uso real. Por ejemplo, puede obtener diferencias de rendimiento notables entre una llamada a función en una lista de comprensión frente a una expresión en línea; no está claro si realmente deseaba lo primero o si lo redujo a eso para que sus casos sean similares.
Usted dice que no importa si usted termina con una matriz o una numpy list
, pero si usted está haciendo este tipo de micro-optimización que lo hace materia, ya que los llevará a cabo de manera diferente cuando se utilízalos después. Poner el dedo en eso podría ser complicado, así que con suerte todo el problema es discutible como prematuro.
Por lo general, es mejor simplemente usar la herramienta adecuada para el trabajo para mayor claridad, legibilidad, etc. Es raro que me resulte difícil decidir entre estas cosas.
- Si necesito matrices numpy, las usaría. Yo los usaría para almacenar grandes matrices homogéneas o datos multidimensionales. Los uso mucho, pero rara vez creo que me gustaría usar una lista.
- Si yo estaba usando estos, me gustaría hacer mi mejor esfuerzo para escribir mis funciones ya vectorizado por lo que no tenía que usar
numpy.vectorize
. Por ejemplo, times_five
a continuación se puede utilizar en una matriz numpy sin decoración.
- Si no tenía motivos para utilizar numpy, es decir, si yo no estaba resolviendo problemas matemáticos numéricos o el uso de características especiales numpy o almacenamiento de matrices multidimensionales o lo que sea ...
- Si Tenía una función ya existente, usaría
map
. Para eso es para eso.
- Si tuviera una operación que se ajustara a una expresión pequeña y no necesitara una función, usaría una lista de comprensión.
- Si solo quisiera hacer la operación para todos los casos pero en realidad no necesito almacenar el resultado, usaría un ciclo simple.
- En muchos casos, utilizaría realmente
map
y enumeraré los equivalentes perezosos de las comprensiones: itertools.imap
y expresiones de generador. Estos pueden reducir el uso de memoria por un factor de n
en algunos casos y pueden evitar realizar operaciones innecesarias a veces.
Si lo hace llegar aquí es donde se encuentran los problemas de rendimiento, recibiendo este tipo de cosas es complicado derecha. Es muy común que las personas el tiempo de la caja de juguetes equivocada para sus problemas reales. Peor aún, es extremadamente común que las personas hagan reglas generales tontas basadas en eso.
considerar los siguientes casos (timeme.py se publican a continuación)
python -m timeit "from timeme import x, times_five; from numpy import vectorize" "vectorize(times_five)(x)"
1000 loops, best of 3: 924 usec per loop
python -m timeit "from timeme import x, times_five" "[times_five(item) for item in x]"
1000 loops, best of 3: 510 usec per loop
python -m timeit "from timeme import x, times_five" "map(times_five, x)"
1000 loops, best of 3: 484 usec per loop
Un obsever ingenuo concluiría que el mapa es el de mejor desempeño de estas opciones, pero la respuesta sigue siendo "depende". Considere el poder de usar los beneficios de las herramientas que está utilizando: las listas de comprensión le permiten evitar la definición de funciones simples; Numpy te permite vectorizar cosas en C si estás haciendo las cosas bien.
python -m timeit "from timeme import x, times_five" "[item + item + item + item + item for item in x]"
1000 loops, best of 3: 285 usec per loop
python -m timeit "import numpy; x = numpy.arange(1000)" "x + x + x + x + x"
10000 loops, best of 3: 39.5 usec per loop
Pero eso no es todo, hay más. Considere el poder de un cambio de algoritmo. Puede ser aún más dramático.
python -m timeit "from timeme import x, times_five" "[5 * item for item in x]"
10000 loops, best of 3: 147 usec per loop
python -m timeit "import numpy; x = numpy.arange(1000)" "5 * x"
100000 loops, best of 3: 16.6 usec per loop
A veces, un cambio de algoritmo puede ser aún más eficaz. Esto será más y más efectivo a medida que los números se hacen más grandes.
python -m timeit "from timeme import square, x" "map(square, x)"
10 loops, best of 3: 41.8 msec per loop
python -m timeit "from timeme import good_square, x" "map(good_square, x)"
1000 loops, best of 3: 370 usec per loop
Y aún ahora, todo esto puede tener poca relación con su problema real. Parece que numpy es tan genial si puedes usarlo correctamente, pero tiene sus limitaciones: ninguno de estos ejemplos numpy usa objetos reales de Python en las matrices. Eso complica lo que debe hacerse; mucho, incluso ¿Y qué pasa si usamos C tipo de datos? Estos son menos robustos que los objetos de Python. Ellos no son Nullable. Los enteros se desbordan. Tienes que hacer un trabajo extra para recuperarlos. Están tipicamente tipificados. Algunas veces estas cosas prueban ser problemas, incluso inesperados.
Así que ahí tienes: una respuesta definitiva. "Depende."
# timeme.py
x = xrange(1000)
def times_five(a):
return a + a + a + a + a
def square(a):
if a == 0:
return 0
value = a
for i in xrange(a - 1):
value += a
return value
def good_square(a):
return a ** 2
por qué no tratar de temporización que? – mpen