2010-01-05 21 views
10

Tengo una matriz Numpy y una lista de índices cuyos valores me gustaría incrementar en uno. Esta lista puede contener índices repetidos, y me gustaría que el incremento se escale con el número de repeticiones de cada índice. Sin repeticiones, el comando es simple:Incrementar matriz numerada con índices repetidos

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

Con repeticiones, se me ha ocurrido con el método siguiente.

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 

¿Es esta la mejor manera? ¿Existe algún riesgo al suponer que las operaciones np.bincount y np.unique darían como resultado el mismo orden ordenado? ¿Me estoy perdiendo alguna operación simple de Numpy para resolver esto?

+1

Tenga en cuenta que numpy.zeros (6). astype ('int') está mejor escrito como numpy.zeros (6, int). – EOL

Respuesta

5

Después de hacer

bbins=np.bincount(b) 

por qué no hacer:

a[:len(bbins)] += bbins 

(. Editado para una mayor simplificación)

+0

¿No sería más lento, cuando b contiene solo unos pocos números de contenedor grandes? – EOL

+0

Sí, en ese caso será más lento que un simple bucle de Python, pero aún más rápido que el código de OP. Hice una prueba de tiempo rápida con 'b = [99999, 99997, 99999]', y 'a = np.zeros (1000, 'int')'. Los tiempos son: OP: 2.5 ms, mía: 495 us, loop simple: 84 us. –

+0

Esto funciona bien. Un bucle simple generalmente ha sido más lento en mi programa. Gracias. – fideli

-4

¿Por qué no?

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

Si b es una pequeña subrango de a, se puede refina la respuesta de Alok como esta:

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

En numpy> = 1.8, también puede utilizar el método at de la adición 'universal function' ('ufunc'). A medida que el docs note:

Para la adición ufunc, este método es equivalente a una [índices] + = b, excepto que los resultados se acumulan para los elementos que están indexadas más de una vez.

Así que tomar su ejemplo:

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

... a continuación ...

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

... dejará a como ...

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

¡Esta solución es la más elegante AFAIK! –

Cuestiones relacionadas