Pregunta

Suponga que tiene una matriz de valores que necesitarán ser sumadas juntas

d = [1,1,1,1,1]

y una segunda matriz que especifica que necesitan ser sumada juntos elementos

i = [0,0,1,2,2]

El resultado se almacena en una nueva matriz de tamaño max(i)+1. Así, por ejemplo i=[0,0,0,0,0] sería equivalente a la suma de todos los elementos de d y almacenando el resultado en la posición 0 de una nueva matriz de tamaño 1.

He intentado poner en práctica esta utilizando

c = zeros(max(i)+1)
c[i] += d

Sin embargo, la operación += añade cada elemento de una sola vez, dando así el resultado inesperado de

[1,1,1]

en lugar de

[2,1,2]

¿Cómo se podría aplicar correctamente este tipo de sumatoria?

¿Fue útil?

Solución

Esta solución debe ser más eficientes para grandes matrices (que itera sobre los posibles valores de índice en lugar de las entradas individuales de i):

import numpy as np

i = np.array([0,0,1,2,2])
d = np.array([0,1,2,3,4])

i_max = i.max()
c = np.empty(i_max+1)
for j in range(i_max+1):
    c[j] = d[i==j].sum()

print c
[1. 2. 7.]

Otros consejos

Si entiendo bien la pregunta, hay una función rápida para esto (siempre y cuando la matriz de datos es 1d)

>>> i = np.array([0,0,1,2,2])
>>> d = np.array([0,1,2,3,4])
>>> np.bincount(i, weights=d)
array([ 1.,  2.,  7.])

retornos np.bincount una matriz para todos los números enteros rango (max (i)), incluso si algunos recuentos son cero

El comentario de Juh_ es la solución más eficiente. código aquí está funcionando:

import numpy as np
import scipy.ndimage as ni

i = np.array([0,0,1,2,2])
d = np.array([0,1,2,3,4])

n_indices = i.max() + 1
print ni.sum(d, i, np.arange(n_indices))
def zeros(ilen):
 r = []
 for i in range(0,ilen):
     r.append(0)

i_list = [0,0,1,2,2]
d = [1,1,1,1,1]
result = zeros(max(i_list)+1)

for index in i_list:
  result[index]+=d[index]

print result

En el caso general cuando se desea submatrices suma por etiquetas que puede utilizar el siguiente código

import numpy as np
from scipy.sparse import coo_matrix

def labeled_sum1(x, labels):
     P = coo_matrix((np.ones(x.shape[0]), (labels, np.arange(len(labels)))))
     res = P.dot(x.reshape((x.shape[0], np.prod(x.shape[1:]))))
     return res.reshape((res.shape[0],) + x.shape[1:])

def labeled_sum2(x, labels):
     res = np.empty((np.max(labels) + 1,) + x.shape[1:], x.dtype)
     for i in np.ndindex(x.shape[1:]):
         res[(...,)+i] = np.bincount(labels, x[(...,)+i])
     return res

El primer método utiliza la multiplicación matriz dispersa. La segunda es la generalización de la respuesta de user333700. Ambos métodos tienen velocidad comparable:

x = np.random.randn(100000, 10, 10)
labels = np.random.randint(0, 1000, 100000)
%time res1 = labeled_sum1(x, labels)
%time res2 = labeled_sum2(x, labels)
np.all(res1 == res2)

Salida:

Wall time: 73.2 ms
Wall time: 68.9 ms
True
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top