Быстрое суммирование массивов numpy по элементам
Скажем, я хочу сделать элементарную сумму списка массивов numpy:
tosum = [rand(100,100) for n in range(10)]
Я искал лучший способ сделать это. Кажется, что numpy.sum ужасен:
timeit.timeit('sum(array(tosum), axis=0)',
setup='from numpy import sum; from __main__ import tosum, array',
number=10000)
75.02289700508118
timeit.timeit('sum(tosum, axis=0)',
setup='from numpy import sum; from __main__ import tosum',
number=10000)
78.99106407165527
Уменьшение намного быстрее (на порядок почти на два порядка):
timeit.timeit('reduce(add,tosum)',
setup='from numpy import add; from __main__ import tosum',
number=10000)
1.131795883178711
Похоже, что сокращение даже имеет значимое преимущество над суммой не numpy (обратите внимание, что они используются для 1e6 пробегов, а не 1e4 для вышеуказанных времен):
timeit.timeit('reduce(add,tosum)',
setup='from numpy import add; from __main__ import tosum',
number=1000000)
109.98814797401428
timeit.timeit('sum(tosum)',
setup='from __main__ import tosum',
number=1000000)
125.52461504936218
Есть ли другие методы, которые я должен попробовать? Кто-нибудь может объяснить рейтинги?
Edit
numpy.sum определенно быстрее, если сначала список преобразуется в массив numpy:
tosum2 = array(tosum)
timeit.timeit('sum(tosum2, axis=0)',
setup='from numpy import sum; from __main__ import tosum2',
number=10000)
1.1545608043670654
Тем не менее, мне только интересно делать сумму один раз, поэтому превращение массива в массив numpy по-прежнему будет иметь реальное ограничение производительности.
Ответы
Ответ 1
Следующее конкурирует с reduce
и работает быстрее, если список tosum
достаточно длинный. Однако, это не намного быстрее, и это больше кода. (reduce(add, tosum)
уверен, довольно.)
def loop_inplace_sum(arrlist):
# assumes len(arrlist) > 0
sum = arrlist[0].copy()
for a in arrlist[1:]:
sum += a
return sum
Сроки для оригинала tosum
. reduce(add, tosum)
быстрее:
In [128]: tosum = [rand(100,100) for n in range(10)]
In [129]: %timeit reduce(add, tosum)
10000 loops, best of 3: 73.5 µs per loop
In [130]: %timeit loop_inplace_sum(tosum)
10000 loops, best of 3: 78 µs per loop
Сроки для гораздо более длинного списка массивов. Теперь loop_inplace_sum
быстрее.
In [131]: tosum = [rand(100,100) for n in range(500)]
In [132]: %timeit reduce(add, tosum)
100 loops, best of 3: 5.09 ms per loop
In [133]: %timeit loop_inplace_sum(tosum)
100 loops, best of 3: 4.4 ms per loop