2010-08-31 13 views
8

Załóżmy masz tablicę wartości, które będą musiały być sumowaneSkumulowane podsumowanie z numpy tablicy przez indeks

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

a druga tablica określająca, które elementy powinny być sumowane

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

Wynik zostanie zapisany w nowej tablicy o rozmiarze max(i)+1. Więc na przykład i=[0,0,0,0,0] byłoby równoważne z sumowaniem wszystkich elementów d i przechowywaniem wyniku na pozycji 0 nowej tablicy o rozmiarze 1.

starałem się wdrożyć to używając

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

Jednak operacja += dodaje każdy element tylko raz, dając w ten sposób nieoczekiwany wynik

[1,1,1] 

zamiast

[2,1,2] 

Jak poprawnie wprowadzić tego rodzaju sumowanie?

+1

Byłoby to o wiele wyraźniejsze, jeśli wartości 'd' były unikalne. Na przykład, jeśli 'd = [0,1,2,3,4]' zgaduję dla 'i = [0,0,0,0,0]' chcesz 'c = [10]', podczas gdy dla 'i = [0,0,1,2,2]' chcesz 'c = [1,2,7]'? – mtrw

+0

Zgadza się. Dzięki za wytłumaczenie. – dzhelil

+0

W takim przypadku rozwiązanie juxstapose ze zmianą sugerowaną w komentarzach powinno załatwić sprawę. – mtrw

Odpowiedz

2

To rozwiązanie powinno być bardziej efektywne w przypadku dużych tablic (to iteracje nad możliwych wartości indeksu zamiast poszczególne wpisy 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

Zamknij, ale myślę, że OP chce 'dla didx, ridx w wyliczeniu (i_list): wynik [ridx] + = d [didx]'. Ponadto, ponieważ znaczniki zawierają [numpy], możesz użyć 'numpy.zeros'. – mtrw

9

Jeśli dobrze rozumiem pytanie, istnieje szybka funkcja ta (o ile tablica danych jest 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 zwraca tablicę dla zakresu wszystkich liczb całkowitych (max (I)), nawet jeśli niektóre liczy są zerowe

+1

to najlepsze rozwiązanie dla przypadku opisanego tutaj.Aby uzyskać ogólną sumę tablic z etykietami, możesz użyć scipy.ndimage.sum. Te moduły mają również inne przydatne funkcje, takie jak maksymalna, minimalna, średnia, wariancja, ... –

2

Komentarz Juh_ jest najbardziej wydajnym rozwiązaniem. Oto kod działa:

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

w ogólnym przypadku, gdy chcemy podsumować podmatryc etykietami można użyć pierwszej metody następujący kod

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 

użyć rzadki mnożenia macierzy. Drugi to uogólnienie odpowiedzi użytkownika333700. Obie metody mają porównywalną szybkość:

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) 

wyjściowa:

Wall time: 73.2 ms 
Wall time: 68.9 ms 
True