2010-01-05 3 views
10

У меня есть массив Numpy и список индексов, значения которых я хотел бы увеличить на единицу. Этот список может содержать повторяющиеся индексы, и я бы хотел, чтобы приращение масштабировалось с количеством повторений каждого индекса. Без повторений команда проста:Прирост массива с повторяющимися индексами

a=np.zeros(6).astype('int') 
b=[3,2,5] 
a[b]+=1 

С повторами я пришел к следующему методу.

b=[3,2,5,2]      # indices to increment by one each replicate 
bbins=np.bincount(b) 
b.sort()      # sort b because bincount is sorted 
incr=bbins[np.nonzero(bbins)] # create increment array 
bu=np.unique(b)     # sorted, unique indices (len(bu)=len(incr)) 
a[bu]+=incr 

Это лучший способ? Есть ли риск, связанный с тем, что операции np.bincount и np.unique приведут к тому же упорядоченному порядку? Неужели я пропустил какую-то простую операцию Numpy, чтобы решить эту проблему?

+1

Обратите внимание, что numpy.zeros (6). astype ('int') лучше записывается как numpy.zeros (6, int). – EOL

ответ

5

После выполнения

bbins=np.bincount(b) 

почему бы не сделать:

a[:len(bbins)] += bbins 

(. Ред для дальнейшего упрощения)

+0

Не будет ли это медленнее, если b содержит только несколько больших номеров бинов? – EOL

+0

Да, в этом случае он будет медленнее, чем простой цикл Python, но все же быстрее, чем код OP. Я проверил быструю проверку времени с помощью 'b = [99999, 99997, 99999]' и 'a = np.zeros (1000, 'int')'. Сроки: OP: 2,5 мс, мой: 495 us, простой цикл: 84 us. –

+0

Это хорошо работает. Простой цикл, как правило, был медленнее в моей программе. Благодарю. – fideli

-4

Почему нет?

for i in b: 
    a[i] += 1 
1

Если b небольшой поддиапазон a, можно уточните ответ Алока следующим образом:

import numpy as np 
a = np.zeros(100000, int) 
b = np.array([99999, 99997, 99999]) 

blo, bhi = b.min(), b.max() 
bbins = np.bincount(b - blo) 
a[blo:bhi+1] += bbins 

print a[blo:bhi+1] # 1 0 2 
10

В numpy> = 1.8 вы также можете использовать метод добавления универсальной функции добавления ('ufunc') at. Как docs note:

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

Так что, ваш пример:

a = np.zeros(6).astype('int') 
b = [3, 2, 5, 2] 

... чтобы потом ...

np.add.at(a, b, 1) 

... оставит a как ...

array([0, 0, 2, 1, 0, 1]) 
+2

Это решение является самым элегантным AFAIK! –

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