Быстрое суммирование массивов numpy по элементам - программирование
Подтвердить что ты не робот

Быстрое суммирование массивов 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 по-прежнему будет иметь реальное ограничение производительности.

4b9b3361

Ответ 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