¿Existe alguna biblioteca estándar / equivalente numpy de la siguiente función:
def augmented_assignment_sum(iterable, start=0):
for n in iterable:
start += n
return start
?
Si bien sum(ITERABLE)
es muy elegante, utiliza +
operador en lugar de +=
, lo que en el caso de los np.ndarray
objetos puede afectar el rendimiento.
He probado que mi función puede ser tan rápida como sum()
(mientras que su uso equivalente +
es mucho más lento). Como es una función pura de Python, supongo que su rendimiento sigue siendo perjudicado, por lo que estoy buscando alguna alternativa:
In [49]: ARRAYS = [np.random.random((1000000)) for _ in range(100)]
In [50]: def not_augmented_assignment_sum(iterable, start=0):
...: for n in iterable:
...: start = start + n
...: return start
...:
In [51]: %timeit not_augmented_assignment_sum(ARRAYS)
63.6 ms ± 8.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [52]: %timeit sum(ARRAYS)
31.2 ms ± 2.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [53]: %timeit augmented_assignment_sum(ARRAYS)
31.2 ms ± 4.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [54]: %timeit not_augmented_assignment_sum(ARRAYS)
62.5 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [55]: %timeit sum(ARRAYS)
37 ms ± 9.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [56]: %timeit augmented_assignment_sum(ARRAYS)
27.7 ms ± 2.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
He intentado usar functools.reduce
combinado con operator.iadd
, pero su rendimiento es similar:
In [79]: %timeit reduce(iadd, ARRAYS, 0)
33.4 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [80]: %timeit reduce(iadd, ARRAYS, 0)
29.4 ms ± 2.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
También estoy interesado en la eficiencia de la memoria, por lo tanto, prefiero asignaciones aumentadas ya que no requieren la creación de objetos intermedios.
np.add.reduce(ARRAYS)
?374 ms ± 83.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
:-( Aunque es considerablemente más rápido siARRAYS
es una matriz 2D.axis=0
. Luego toma355 ms ± 16.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
:-( Internamente usanp.add.reduce()
(numpy v. 1.15.4)np.dot(your_array, np.ones(len(your_array)))
. Debería transferirse a BLAS y ser razonablemente rápido.Respuestas:
La respuesta a la pregunta principal --- Espero que @Martijn Pieters perdone mi elección de metáfora --- directamente de la boca del caballo es: No, no existe tal construcción.
Si permitimos que algunas líneas de código implementen tal equivalente, obtenemos una imagen bastante complicada con lo que es más rápido dependiendo del tamaño del operando:
Este gráfico muestra los tiempos de los diferentes métodos en relación con
sum
el tamaño de los operandos, el número de términos siempre es 100.augmented_assignment_sum
comienza a dar resultados para tamaños de operandos relativamente grandes. Usar unscipy.linalg.blas.*axpy
aspecto bastante competitivo en la mayor parte del rango probado, su principal inconveniente es que es mucho menos fácil de usar quesum
.Código:
fuente