Ich weiß nicht, ob steigt viel schneller, aber Ihre Iteration kann mit
for i,j in zip(*C):
D[j].add(i)
rationalisiert werden Ein defaultdict könnte dieser Aufgabe einen netten Touch hinzufügen:
In [58]: from collections import defaultdict
In [59]: D=defaultdict(set)
In [60]: for i,j in zip(*C):
D[j].add(i)
In [61]: D
Out[61]: defaultdict(<class 'set'>, {0: {0, 2, 3, 4, 5}, 1: {1, 3, 4}, 2: {1, 2, 6, 7}, 3: {1, 3, 4, 6}, 4: {1, 2, 6, 7}, 5: {0, 2, 3}})
In [62]: dict(D)
Out[62]:
{0: {0, 2, 3, 4, 5},
1: {1, 3, 4},
2: {1, 2, 6, 7},
3: {1, 3, 4, 6},
4: {1, 2, 6, 7},
5: {0, 2, 3}}
Eine Alternative mit spärlichen Matrizen ist das lil
Format, das die Daten eine Liste von Listen speichert. Da Sie durch Spalte sammeln Daten möchten, stellen Sie die Matrix aus A.T
(transponieren)
In [70]: M=sparse.lil_matrix(A.T)
In [71]: M.rows
Out[71]:
array([[0, 2, 3, 4, 5], [1, 3, 4], [1, 2, 6, 7], [1, 3, 4, 6],
[1, 2, 6, 7], [0, 2, 3]], dtype=object)
, die die gleichen Listen sind.
Für diese kleine Fall direkten Iteration ist schneller als spärlich
In [72]: %%timeit
....: D=defaultdict(set)
....: for i,j in zip(*C):
D[j].add(i)
....:
10000 loops, best of 3: 24.4 µs per loop
In [73]: %%timeit
....: D=[set() for j in range(A.shape[1])]
....: for i,j in zip(*C):
D[j].add(i)
....:
10000 loops, best of 3: 22.9 µs per loop
In [74]: %%timeit
....: M=sparse.lil_matrix(A.T)
....: M.rows
....:
1000 loops, best of 3: 588 µs per loop
In [75]: %%timeit
....: C=sparse.csc_matrix(A)
....: D = [set(C.indices[C.indptr[i]:C.indptr[i+1]]) for i in range(C.shape[1])] ....:
1000 loops, best of 3: 476 µs per loop
Für eine große Auswahl, die Rüstzeit für die spärliche Matrix weniger signifikant.
==========================
Haben wir wirklich set
brauchen? Eine Variation des lil
Ansatz ist mit der Transponierten nonzero
auf dem, das heißt, durch Spalte
In [90]: C=np.nonzero(A.T)
# (array([0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5], dtype=int32),
# array([0, 2, 3, 4, 5, 1, 3, 4, 1, 2, 6, 7, 1, 3, 4, 6, 1, 2, 6, 7, 0, 2, 3], dtype=int32))
Die Zahlen sind alle dort zu beginnen; wir müssen nur die zweite Liste in Stücke aufgeteilt auf die ersten
In [91]: i=np.nonzero(np.diff(C[0]))[0]+1
In [92]: np.split(C[1],i)
Out[92]:
[array([0, 2, 3, 4, 5], dtype=int32),
array([1, 3, 4], dtype=int32),
array([1, 2, 6, 7], dtype=int32),
array([1, 3, 4, 6], dtype=int32),
array([1, 2, 6, 7], dtype=int32),
array([0, 2, 3], dtype=int32)]
entsprechen Dies ist langsamer als die direkte Iteration, aber ich vermute, dass es besser skaliert; möglicherweise auch eine der spärlichen Alternativen:
In [96]: %%timeit
C=np.nonzero(A.T)
....: i=np.nonzero(np.diff(C[0]))[0]+1
....: np.split(C[1],i)
....:
10000 loops, best of 3: 55.2 µs per loop
Awesome, diese Ansatz ist etwa doppelt so schnell wie mein ursprünglicher Code. Vielen Dank! – ToneDaBass
Auf größeren Sparse-Arrays finde ich das 'np.nonzero (A)' und 'sparse.csc_matrix (A) 'nehmen ungefähr die gleiche Zeit. Und es ist ziemlich viel größer als die Iteration, die Sätze sammelt. – hpaulj