2010-08-31 23 views
8

Angenommen, es soll ein Array von Werten haben, die miteinander summiert werden müssenCumulative Summation einer numpy Array von Index

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

und ein zweites Feld angibt, welche Elemente müssen aufsummiert werden

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

Das Ergebnis wird in einem neuen Array der Größe max(i)+1 gespeichert. So wäre zum Beispiel i=[0,0,0,0,0] äquivalent zum Summieren aller Elemente von d und Speichern des Ergebnisses an Position 0 eines neuen Arrays der Größe 1. mit

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

jedoch

Ich habe versucht, dies zu implementieren, das += Betrieb jedes Element fügt nur einmal, so das unerwartete Ergebnis von

[1,1,1] 

geben statt

[2,1,2] 

Wie würde man diese Art von Summierung richtig umsetzen?

+1

Dieses viel klarer sein würde, wenn die Werte von 'd' einzigartig waren. Zum Beispiel, wenn 'd = [0,1,2,3,4] 'Ich rate für' i = [0,0,0,0,0]' Sie wollen 'c = [10]', während für 'i = [0,0,1,2,2]' willst du 'c = [1,2,7]'? – mtrw

+0

Das ist richtig. Danke fürs klarstellen. – dzhelil

+0

In diesem Fall sollte juxstaposes Lösung, mit der Änderung, die ich in den Kommentaren vorschlage, den Trick machen. – mtrw

Antwort

2

Diese Lösung sollte für große Arrays effizienter sein (es die möglichen Indexwerte iteriert statt die einzelnen Einträge von 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

Schließen, aber ich denke, das OP will 'für didx, ridx in enumerate (i_list): Ergebnis [ridx] + = d [didx]'. Da die Tags [numpy] enthalten, können Sie auch 'numpy.zeros' verwenden. – mtrw

9

Wenn ich die Frage richtig verstanden habe, gibt es eine schnelle Funktion für diese (solange das Datenarray ist 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 ein Array liefert für alle ganzen Zahlen Bereich (max (i)), auch wenn einige Zählwerte null

+1

das ist die beste Lösung für den hier beschriebenen Fall.Für eine allgemeine Summe des markierten Arrays können Sie scipy.ndimage.sum verwenden. Diese Module haben auch andere nützliche Funktionen wie Maximum, Minimum, Mittelwert, Varianz, ... –

2

Juh_'s Kommentar ist die effizienteste Lösung. Hier arbeitet Code:

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

Im allgemeinen Fall, wenn Sie wollen Untermatrizen von Etiketten summieren können Sie den folgenden Code

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 

Die erste Methode verwenden, um die spärliche Matrix-Multiplikation verwenden. Der zweite ist die Verallgemeinerung der Antwort von user333700. Beide Methoden haben vergleichbare Geschwindigkeit:

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) 

Ausgang:

Wall time: 73.2 ms 
Wall time: 68.9 ms 
True 
Verwandte Themen