2010-08-31 8 views
8

Suponga que tiene una matriz de valores que necesitarán ser resumido juntossuma acumulativa de una matriz de numpy por el índice

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

y una segunda matriz que especifica que necesitan ser sumada juntos

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

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

Me trataron de poner en práctica esta usando

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 implementaría correctamente este tipo de resumen?

+1

Esto sería mucho más claro si los valores de 'd' eran únicos. Por ejemplo, si 'd = [0,1,2,3,4]' Supongo que 'i = [0,0,0,0,0]' quiere 'c = [10]', mientras para 'i = [0,0,1,2,2]' ¿quieres 'c = [1,2,7]'? – mtrw

+0

Eso es correcto. Gracias por aclararlo. – dzhelil

+0

En ese caso, la solución de juxstapose, con el cambio que sugiero en los comentarios, debería hacer el truco. – mtrw

Respuesta

2

Esta solución debe ser más eficiente para grandes conjuntos (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.] 
2
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 
+2

Cerrar, pero creo que el OP quiere 'para didx, ridx en enumerar (i_list): resultado [ridx] + = d [didx]'. Además, dado que las etiquetas incluyen [numpy], puede usar 'numpy.zeros'. – mtrw

9

Si entiendo bien la pregunta, hay una función rápida para este (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.]) 

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

+1

esa es la mejor solución para el caso descrito aquí.Para una suma general de matriz etiquetada, puede usar scipy.ndimage.sum. Estos módulos también tienen otras funciones útiles, como máxima, mínima, media, varianza, ... –

2

El comentario de Juh_ es la solución más eficiente. Aquí está el código de trabajo:

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)) 
0

En el caso general, cuando se quiere resumir submatrices de etiquetas se 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 de matrices dispersas. El segundo es la generalización de la respuesta del usuario333700. Ambos métodos tienen una 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 
Cuestiones relacionadas