2010-01-05 4 views
10

Ho una matrice Numpy e un elenco di indici i cui valori vorrei incrementare di uno. Questo elenco può contenere indici ripetuti e vorrei che l'incremento si ridimensionasse con il numero di ripetizioni di ciascun indice. Senza ripetizioni, il comando è semplice:Incremento array Numpy con indici ripetuti

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

Con ripetizioni, ho trovato il seguente metodo.

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 

È questo il modo migliore? C'è il rischio che si assuma che le operazioni e np.unique risultino nello stesso ordine ordinato? Mi manca qualche semplice operazione di Numpy per risolvere questo?

+1

noti che numpy.zeros (6). astype ('int') è scritto meglio come numpy.zeros (6, int). – EOL

risposta

5

Dopo aver fatto

bbins=np.bincount(b) 

perché non farlo:

a[:len(bbins)] += bbins 

(. A cura di semplificare ulteriormente)

+0

Non dovrebbe essere più lento, quando b contiene solo alcuni numeri di contenitori grandi? – EOL

+0

Sì, sarà più lento di un semplice ciclo Python in quel caso, ma ancora più veloce del codice OP. Ho fatto un test rapido con 'b = [99999, 99997, 99999]', e 'a = np.zeros (1000, 'int')'. I tempi sono: OP: 2,5 ms, mio: 495 us, loop semplice: 84 us. –

+0

Funziona bene. Un ciclo semplice è stato generalmente più lento nel mio programma. Grazie. – fideli

-4

Perché no?

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

Se b è un piccolo sottoinsieme di a, si può raffina la risposta di Alok in questo modo:

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

In numpy> = 1,8, è anche possibile utilizzare il metodo at dell'aggiunta 'funzione universale' ('ufunc'). Come docs note:

Per aggiunta ufunc, questo metodo è equivalente ad un [indici] + = b, tranne che i risultati vengono accumulati per gli elementi che sono indicizzati più di una volta.

Quindi, prendendo il tuo esempio:

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

... per poi ...

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

... lascerà a come ...

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

Questa soluzione è la più elegante AFAIK! –