50

scipy.sparseを使用してスパース行列のゼロ以外のエントリを反復処理するのが最善の方法だと思います。たとえば、次のようにすると、次のようになります。

from scipy.sparse import lil_matrix

x = lil_matrix( (20,1) )
x[13,0] = 1
x[15,0] = 2

c = 0
for i in x:
  print c, i
  c = c+1

出力は

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13   (0, 0) 1.0
14 
15   (0, 0) 2.0
16 
17 
18 
19  

したがって、イテレータはゼロ以外のエントリだけでなく、すべての要素にアクセスしているように見えます。APIを見てきました

http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.lil_matrix.html

少し検索しましたが、うまくいく解決策が見つからないようです。

4

6 に答える 6

77

編集:bbtrbのメソッドcoo_matrixを使用)は、ゼロ以外を使用した元の提案よりもはるかに高速です。Sven Marnachの使用の提案itertools.izipも、速度を向上させます。現在の最速はusing_tocoo_izip

import scipy.sparse
import random
import itertools

def using_nonzero(x):
    rows,cols = x.nonzero()
    for row,col in zip(rows,cols):
        ((row,col), x[row,col])

def using_coo(x):
    cx = scipy.sparse.coo_matrix(x)    
    for i,j,v in zip(cx.row, cx.col, cx.data):
        (i,j,v)

def using_tocoo(x):
    cx = x.tocoo()    
    for i,j,v in zip(cx.row, cx.col, cx.data):
        (i,j,v)

def using_tocoo_izip(x):
    cx = x.tocoo()    
    for i,j,v in itertools.izip(cx.row, cx.col, cx.data):
        (i,j,v)

N=200
x = scipy.sparse.lil_matrix( (N,N) )
for _ in xrange(N):
    x[random.randint(0,N-1),random.randint(0,N-1)]=random.randint(1,100)

timeit次の結果が得られます。

% python -mtimeit -s'import test' 'test.using_tocoo_izip(test.x)'
1000 loops, best of 3: 670 usec per loop
% python -mtimeit -s'import test' 'test.using_tocoo(test.x)'
1000 loops, best of 3: 706 usec per loop
% python -mtimeit -s'import test' 'test.using_coo(test.x)'
1000 loops, best of 3: 802 usec per loop
% python -mtimeit -s'import test' 'test.using_nonzero(test.x)'
100 loops, best of 3: 5.25 msec per loop
于 2010-11-30T21:57:09.100 に答える
38

最速の方法は、次のように変換することcoo_matrixです。

cx = scipy.sparse.coo_matrix(x)

for i,j,v in zip(cx.row, cx.col, cx.data):
    print "(%d, %d), %s" % (i,j,v)
于 2010-11-30T22:05:22.367 に答える
2

tocoo() は、マトリックス全体を別の構造に実体化しますが、これは Python 3 で推奨される MO ではありません。この反復子も考慮することができます。これは、特に大きなマトリックスに役立ちます。

from itertools import chain, repeat
def iter_csr(matrix):
  for (row, col, val) in zip(
    chain(*(
          repeat(i, r)
          for (i,r) in enumerate(comparisons.indptr[1:] - comparisons.indptr[:-1])
    )),
    matrix.indices,
    matrix.data
  ):
    yield (row, col, val)

私はおそらくnumpy-constructs(特にenumerate)に置き換える必要がある多くのpython-constructsを使用していることを認めなければなりません。

:

In [43]: t=time.time(); sum(1 for x in rather_dense_sparse_matrix.data); print(time.time()-t)
52.48686504364014
In [44]: t=time.time(); sum(1 for x in enumerate(rather_dense_sparse_matrix.data)); print(time.time()-t)
70.19013023376465
In [45]: rather_dense_sparse_matrix
<99829x99829 sparse matrix of type '<class 'numpy.float16'>'
with 757622819 stored elements in Compressed Sparse Row format>

はい、列挙はやや遅いです(っぽい)

イテレータの場合:

In [47]: it = iter_csr(rather_dense_sparse_matrix)
In [48]: t=time.time(); sum(1 for x in it); print(time.time()-t)
113.something something

したがって、このオーバーヘッドが許容できるかどうかを判断します。私の場合は tocoo が原因MemoryOverflowsです。

IMHO: そのようなイテレータは、dict() の items() と同様に、csr_matrix インターフェイスの一部である必要があります :)

于 2015-07-06T11:11:50.877 に答える
1

私は同じ問題を抱えていました。実際、あなたの関心が速度だけである場合、最速の方法(1桁以上高速)は、疎行列を密行列(x.todense())に変換し、ゼロ以外を反復することです密行列の要素。(もちろん、このアプローチにはより多くのメモリが必要です)

于 2010-12-28T16:18:14.773 に答える
0

filter(lambda x:x, x)の代わりに試してくださいx

于 2010-11-30T21:56:20.753 に答える