Existe algum equivalente padrão de biblioteca / numpy da seguinte função:
def augmented_assignment_sum(iterable, start=0):
for n in iterable:
start += n
return start
?
Embora sum(ITERABLE)
seja muito elegante, ele usa +
operador em vez de +=
, o que, no caso de np.ndarray
objetos, pode afetar o desempenho.
Eu testei que minha função pode ser tão rápida quanto sum()
(enquanto seu uso equivalente +
é muito mais lento). Como é uma função Python pura, acho que seu desempenho ainda é deficiente, portanto, estou procurando alguma 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)
Eu tentei usar functools.reduce
combinado com operator.iadd
, mas seu desempenho é semelhante:
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)
Também estou interessado em eficiência de memória, portanto, prefiro atribuições aumentadas, pois não exigem a criação de objetos intermediários.
np.add.reduce(ARRAYS)
?374 ms ± 83.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
:-( Embora seja consideravelmente mais rápido seARRAYS
for um array 2D. #axis=0
. Em seguida, ele leva355 ms ± 16.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
:-( Internamente ele usanp.add.reduce()
(v numpy 1.15.4.)np.dot(your_array, np.ones(len(your_array)))
. Deve transferir para o BLAS e ser razoavelmente rápido.Respostas:
A resposta para a pergunta principal --- Espero que @Martijn Pieters perdoe minha escolha de metáfora --- direto da boca do cavalo é: Não, não existe esse recurso.
Se permitirmos que algumas linhas de código implementem esse equivalente, obteremos uma imagem bastante complicada com o que é mais rápido, dependendo do tamanho do operando:
Este gráfico mostra tempos de métodos diferentes em relação ao
sum
tamanho acima do operando, o número de termos é sempre 100.augmented_assignment_sum
começa a dar frutos em tamanhos relativamente grandes de operandos. O usoscipy.linalg.blas.*axpy
parece bastante competitivo na maior parte da faixa testada, sendo sua principal desvantagem muito menos fácil de usar do quesum
.Código:
fonte