numpy: Zeilen einer Matrix effizient hinzufügen

Ich habe eine Matrix.

mat = array([
   [ 0,  1,  2,  3],
   [ 4,  5,  6,  7],
   [ 8,  9, 10, 11]
   ])

Ich möchte die Summe der Zeilen bei bestimmten Indizes erhalten: zB

ixs = np.array([0,2,0,0,0,1,1])

Ich weiß, dass ich die Antwort berechnen kann als:

mat[ixs].sum(axis=0)
> array([16, 23, 30, 37])

Das Problem ist, dass ixs sehr lang sein kann und ich nicht den gesamten Speicher verwenden möchte, um die Zwischenproduktmatte [ixs] zu erstellen, sondern nur, um sie erneut mit der Summe zu reduzieren.

Ich weiß auch, dass ich einfach die Indizes hochzählen und stattdessen die Multiplikation verwenden könnte.

np.bincount(ixs, minlength=mat.shape[0).dot(mat)
> array([16, 23, 30, 37])

Aber das wird teuer, wenn meine ixs spärlich sind.

Ich weiß über die spärlichen Matrizen von scipy Bescheid, und ich nehme an, ich könnte sie verwenden, aber ich würde eine reine Numpy-Lösung vorziehen, da spärliche Matrizen auf verschiedene Arten begrenzt sind (z. B. nur 2-d).

Also, gibt es in diesem Fall einen reinen Weg, die Indizierung und Summenreduzierung zusammenzuführen?

Fazit:

Danke Divakar und hpaulj für deine sehr gründlichen Antworten. Mit "spärlich" meine ich, dass die meisten Werte inrange(w.shape[0]) sind nicht in ixs. Unter Verwendung dieser neuen Definition (und mit einer realistischeren Datengröße führte ich Divakar-Tests erneut durch, wobei einige neue Funktionen hinzugefügt wurden:

rng = np.random.RandomState(1234)
mat = rng.randn(1000, 500)
ixs = rng.choice(rng.randint(mat.shape[0], size=mat.shape[0]/10), size=1000)

# Divakar's solutions
In[42]: %timeit org_indexing_app(mat, ixs)
1000 loops, best of 3: 1.82 ms per loop
In[43]: %timeit org_bincount_app(mat, ixs)
The slowest run took 4.07 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 177 µs per loop
In[44]: %timeit indexing_modified_app(mat, ixs)
1000 loops, best of 3: 1.81 ms per loop
In[45]: %timeit bincount_modified_app(mat, ixs)
1000 loops, best of 3: 258 µs per loop
In[46]: %timeit simply_indexing_app(mat, ixs)
1000 loops, best of 3: 1.86 ms per loop
In[47]: %timeit take_app(mat, ixs)
1000 loops, best of 3: 1.82 ms per loop
In[48]: %timeit unq_mask_einsum_app(mat, ixs)
10 loops, best of 3: 58.2 ms per loop 
# hpaulj's solutions
In[53]: %timeit hpauljs_sparse_solution(mat, ixs)
The slowest run took 9.34 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 524 µs per loop
%timeit hpauljs_second_sparse_solution(mat, ixs)
100 loops, best of 3: 9.91 ms per loop
# Sparse version of original bincount solution (see below):
In[60]: %timeit sparse_bincount(mat, ixs)
10000 loops, best of 3: 71.7 µs per loop

Der Gewinne ist in diesem Fall die spärliche Version der Bincount-Lösung.

def sparse_bincount(mat, ixs):
    x = np.bincount(ixs)
    nonzeros, = np.nonzero(x)
    x[nonzeros].dot(mat[nonzeros])

Antworten auf die Frage(6)

Ihre Antwort auf die Frage