Вы правы, новый массив будет выделен для каждого промежуточного результата.К счастью, пакет numexpr
предназначен для решения этой проблемы.Из описания:
Основная причина, по которой NumExpr достигает лучшей производительности, чем NumPy, заключается в том, что он избегает выделения памяти для промежуточных результатов.Это приводит к лучшему использованию кэша и уменьшает доступ к памяти в целом.Благодаря этому NumExpr лучше всего работает с большими массивами.
Пример:
In [97]: xs = np.random.rand(1_000_000)
In [98]: %timeit xs ** 3 + xs ** 2 + xs
26.8 ms ± 371 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [99]: %timeit numexpr.evaluate('xs ** 3 + xs ** 2 + xs')
1.43 ms ± 20.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Благодаря @ max9111 за указание на то, что числоxpr упрощает умножение.Похоже, что большая часть расхождений в тесте объясняется оптимизацией xs ** 3
.
In [421]: %timeit xs * xs
1.62 ms ± 12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [422]: %timeit xs ** 2
1.63 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [423]: %timeit xs ** 3
22.8 ms ± 283 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [424]: %timeit xs * xs * xs
2.52 ms ± 58.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)