2017-02-09 3 views
3

у меня есть пустой массив:Векторизованная сумма массива по показателям второго массива

empty = np.array([0, 0, 0, 0, 0]) 

массив индексов, соответствующих позиции в моем массиве пустых

ind = np.array([2, 3, 1, 2, 4, 2, 4, 2, 1, 1, 1, 2]) 

и массив значений

val = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 

Я хочу добавить значения в 'val' в 'empty' в соответствии с положением, заданным 'ind'.

Не-Векторизованное решение:

for i, v in zip(ind, val): maps[i] += v 
>>> maps 
[ 0. 4. 5. 1. 2.] 

Моих фактических массивов является многогранным и поэтому я займет слишком много у меня есть Жажды скорости Я действительно хочу Векторизованное решение, или решения, которое очень быстро ,

Примечание это не работает:

maps[ind] += val 
>>> maps 
array([ 0., 1., 1., 1., 1.]) 

Я был бы признателен за дополнительную решение, которое работает в Python 2.7, 3.5, 3.6, без икоты

+1

это правда, что это дубликат. но мой вопрос намного понятнее. – user6794223

ответ

6

Вы можете использовать np.add.at, который работает эквивалентно empty[ind] += val, за исключением того, что результаты накапливаются для элементов, которые индексируются более одного раза, что дает вам кумулятивный результат для этих индексов.

>>> np.add.at(empty, ind, val) 
>>> empty 
array([0, 4, 5, 1, 2]) 
1

Это в основном histogram, так и в одномерном случае:

h, b = np.histogram(ind, bins=np.arange(empty.size+1), weights=val) 
empty += h 

Конечно, вы можете оставить второе заявление в случае, если пусто имеет только нули.

+0

Я удалил часть о 'np.bincount', потому что @DanielForsman уже дал этот ответ, и я видел только после редактирования. –

2

Что вы ищете, это e=np.bincount(ind, weights=val, minlength=n) где n - длина вашего пустого массива. Таким образом, вам не нужно инициализировать empty. Вам нужно только сделать это в первый раз, а потом вы можете сделать e+=np.bincount(ind, weights=val)

Это, по крайней мере в два раза быстрее, чем np.add.at:

%timeit np.bincount(ind, val, minlength=empty.size) 
The slowest run took 12.69 times longer than the fastest. This could mean that an intermediate result is being cached. 
100000 loops, best of 3: 2.05 µs per loop 

%timeit np.add.at(empty, ind, val) 
The slowest run took 2822.05 times longer than the fastest. This could mean that an intermediate result is being cached. 
100000 loops, best of 3: 4.32 µs per loop 

Как для многомерных индексов, вы можете сделать:

np.bincount(np.ravel_multi_index(ind, empty.shape), np.ravel(val), minlength=empty.size).reshape(empty.shape) 

Я не знаю, как сделать это с np.add.at для сравнения скорости

+0

Должно ли это работать, если пусто и val многомерны? Пример: empty.shape = (5,2,2) и val.shape = (10,2,2)? – user6794223

+1

Не так, как написано, вам нужно будет «ravel_multi_index» ваши индексы, «ravel» 'empty' и' val' и 'reshape' конечные результаты. В этот момент 'np.add.at', вероятно, быстрее или, по крайней мере, больше pythonic. Но это не то, что вы просили :) –

+0

Это не то, что я спросил, вы правы. Я не ожидал, что это будет иметь значение. Но спасибо! – user6794223

Смежные вопросы