未来は僕以外の手の中

SI屋がIT技術やビジネスのことなどを気ままに書き綴ってみるなど

SciPyでの疎行列の扱い、保存など

Python、特にSciPyは日本語でのドキュメントが少ないので、メモがてら記述。


単語文書行列などでは大規模疎行列になることがよくある。
そこで格納方法の工夫などを行っていく必要がある。


最もスタンダードな方法としては圧縮行格納方式などがある。
基本的に疎行列の要素は0なので、非零の要素の位置だけ覚えておこうという発想。
もちろん(?)SciPyには疎行列を扱うモジュールsparseが用意されている。


lil_matrixにて疎行列を生成。引数には行列の大きさ(m, n)を指定。

from numpy import *
from scipy import io, sparse

A = sparse.lil_matrix((3, 3)) # 疎行列生成
A[0,1] = 3
A[1,0] = 2
A[2,2] = 5

【Aの型、中身】
3×3行列であること、および非零の位置のみ格納されていることが分かる。

>>> type(A)
<class 'scipy.sparse.lil.lil_matrix'>
>>> A
<3x3 sparse matrix of type '<type 'numpy.float64'>'
	with 3 stored elements in LInked List format>
>>> print A
(0, 1)  3.0
(1, 0)  2.0
(2, 2)  5.0

通常の行列の形に戻すにはtodense()を使う。

>>> A.todense() # 行列の形に戻す
matrix([[ 0.,  3.,  0.],
        [ 2.,  0.,  0.],
        [ 0.,  0.,  5.]])


matrixの保存にはio.savematを使う。

io.savemat("matrix_a", {"A":A})

これを実行すると「matrix_a.mat」というファイルが生成される。
保存する際には{"A":A}のように辞書のような形で書き込む。
なお、lil_matrix型でも保存できる。


また読み込みはio.loadmatを使う。

>>> A = io.loadmat("matrix_a")["A"]
>>> A.todense()
matrix([[ 0.,  3.,  0.],
        [ 2.,  0.,  0.],
        [ 0.,  0.,  5.]])

大規模疎行列の生成計算を一度きりにしたい場合は
lil_matrix型にて生成およびファイル保存を行い、使い回すと良い。


lil_matrix型とmatrix型における保存ファイルの容量の違いを見てみる。

from numpy import *
from scipy import io, sparse

A = sparse.lil_matrix((1000, 1000))
A.setdiag( ones(1000) ) # 対角要素を1にする
B = A.todense()

io.savemat("matrix_a", {"A":A}) # lil_matrix型で保存
io.savemat("martix_b", {"B":B}) # matrix型で保存

容量チェック

$ ls -lh
-rw-r--r--  1 billest  billest   7.6M  9  7 05:23 martix_b.mat
-rw-r--r--  1 billest  billest    23K  9  7 05:23 matrix_a.mat

これからも疎行列の格納にはlil_matrix型の方が良いことが分かる。当たり前ではあるが…