2016-11-18 4 views
0

У меня есть много матриц для добавления. Предположим, что матрицы - [M1, M2 ..., M_n]. Тогда простой путьэффективный способ создания матрицы в numpy

X = np.zeros() 
for M in matrices: 
    X += M 

В операции X + = M, делает Python создать новую память для X каждый раз + = выполняется? Если это так, это кажется неэффективным. Есть ли способ сделать операцию на месте, не создавая новую память для X?

+0

Что именно у вас есть: '[M1, M2 ..., M_n]'? Это список массивов? Добавить образец? – Divakar

+0

@ Divakar Я думаю, что это список матриц. – TuanDT

+0

@ Дивакар, М - np.ndarray. – DSKim

ответ

1

Это работает, но не быстрее, на моей машине:

numpy.sum(matrices, axis=0) 
0

Если вы не получаете MemoryError, пытаясь вторым использование догадки памяти в NumPy не стоит усилий. Оставьте это разработчикам, которые знают скомпилированный код.

Но мы можем выполнить некоторые тесты времени - это действительно важно, не так ли?

Я проверю добавление массива хорошего размера 100 раз.

In [479]: M=np.ones((1000,1000)) 

Ваш итеративный подход с + =

In [480]: %%timeit 
    ...: X=np.zeros_like(M) 
    ...: for _ in range(100): X+=M 
    ...: 
1 loop, best of 3: 627 ms per loop 

или сделать массив размера (100, 1000, 1000) и применять np.sum через первую ось.

In [481]: timeit np.sum(np.array([M for _ in range(100)]),axis=0) 
1 loop, best of 3: 1.54 s per loop 

и с использованием np.add ufunc. С помощью reduce мы можем последовательно применять его ко всем значениям в списке.

In [482]: timeit np.add.reduce([M for _ in range(100)]) 
1 loop, best of 3: 1.53 s per loop 

np.sum случай дает мне MemoryError, если я использую range(1000). У меня недостаточно памяти для хранения массива (1000,1000,1000). То же самое для add.reduce, который строит массив из списка.

Что касается +=, то под обложкой, как правило, скрывают и не интересуют нас - обычно. Но пик под чехлами смотреть на ufunc.at: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html#numpy.ufunc.at

Выполняет небуферизован в месте эксплуатации на операнде «а» для элементов, определенных «индексами». Для добавления ufunc этот метод эквивалентен [индексам] + = b, за исключением того, что результаты накапливаются для элементов, индексированных более одного раза.

Так X+=M же написать сумму в буфер, а затем копирует этот буфер в X. Существует временный буфер, но использование конечной памяти не меняется. Но создание и копирование буфера выполняется быстрым C-кодом.

np.add.at был добавлен, чтобы иметь дело с случаем, когда это буферное действие создает некоторые проблемы (дублирующие индексы).

Таким образом, это позволяет избежать этого временного буфера, но при значительной скорости. Вероятно, это добавленная возможность индексирования, которая замедляет ее. (Возможно, более справедливый тест add.at, но в этом случае он, конечно же, не поможет.)

In [491]: %%timeit 
    ...: X=np.zeros_like(M) 
    ...: for _ in range(100): np.add.at(X,(slice(None),slice(None)),M) 
1 loop, best of 3: 19.8 s per loop