SciPy.sparseのまとめ

行列内の値の殆どを0で占めるような行列を疎行列といいます。そんな疎行列のデータを圧縮して効率的に計算を行うseipy.sparseについてまとめていきます。
scipy.sparseの疎行列クラス
csr_matrix 圧縮行格納方式
CSR(Compressed Sparse Row)は行ごとに圧縮を行います。
csr_matrix( 配列 )
from scipy.sparse import csr_matrix
ary = [[10, 0, 20],
[0, 30, 40],
[0, 0, 50]]
csr = csr_matrix(ary)
print(csr)
(0, 0) 10
(0, 2) 20
(1, 1) 30
(1, 2) 40
(2, 2) 50
csr_matrix解説
例で作成した配列を図にしてみると下記のようなマトリクス図になります。
青文字は(行,列)を表しています。

この図から(行,列)の位置とそれぞれの値が対応しているのが見てとれます。

更に1行目から順番に見ていくと、出力結果の(0,0) 10, (0,2) 20, (1,1) 30と1行目から順に出力されているのが確認できます。
data属性
マトリクスCSRフォーマットのデータ配列を表します。つまり、値そのものを表しています。
結果は行の順で表示されます。
print(csr.data)
[10 20 30 40 50]
indices属性
マトリクスCSRフォーマットのインデックス配列を表します。 indicesは文字通りインデックス(indicesはindexの複数形)を意味しています。
【例】indicesの出力print(csr.indices)
[0 2 1 2 2]
indices解説
ここで言うインデックスは下記の図の赤丸で囲った数字を指します。

つまり、dataで出力した数字が何列名かを表しており、10なら0、20なら2、という具合にインデックスが設定されています。
行で圧縮するcsrのインデックスは列番号ということになります。
indptr属性
マトリクスCSRフォーマットのインデックスポインタ配列を表します。 ind(インデックス)のptr(ポインタ)ということです。
【例】indptrの出力print(csr.indptr)
[0 2 4 5]
indptr解説
ind(インデックス)のptr(ポインタ)とは下記の図のようなイメージです。
図では矢印がポインタを表しており、それぞれの色と丸印が対応しているポインタの位置を表しています。
ポインタは1行目、2行目、3行目と進んでいきます。

ポインタが青の位置の時(スタート位置の時)、それ以上値が存在しないので個数は0。
ポインタが赤の位置の時、ポインタ位置よりも上にある値は10と20で2個。
ポインタが緑の位置の時、ポインタ位置よりも上にある値は10と20と30と40で4個。
ポインタが黒の位置の時、ポインタ位置よりも上にある値は10と20と30と40と50で5個。
つまり、ポインタの位置によってそれぞれの数字をカウントしていることになります。
csc_matrix 圧縮列格納方式
CSC(Compressed Sparse Column)は列ごとに圧縮を行います。
csc_matrix( 配列 )
from scipy.sparse import csc_matrix
ary = [[10, 0, 20],
[0, 30, 40],
[0, 0, 50]]
csc = csc_matrix(ary)
print(csc)
(0, 0) 10
(1, 1) 30
(0, 2) 20
(1, 2) 40
(2, 2) 50
csc_matrix解説
例で作成した配列を図にしてみると下記のようなマトリクス図になります。
青文字は(行,列)を表しています。

この図から(行,列)の位置とそれぞれの値が対応しているのが見てとれ、更に1列目から順番に見ていくと、出力結果の(0,0) 10, (1,1) 30, (0,2) 20と1列目から順に出力されているのが確認できます。
data属性
マトリクスのデータ配列で、値そのものを意味します。結果は列の順で表示されます。
【例】dataの出力print(csc.data)
[10 30 20 40 50]
indices属性
CSCフォーマットのインデックス配列を表します。つまり値の位置を示すインデックスを出力します。
【例】indicesの出力print(csc.indices)
[0 1 0 1 2]
indices解説
インデックスとは下記の図の赤丸で囲った数字を指します。

つまり、dataで出力した数字が何行目かを表しており、10なら0、30なら1、20なら0、という具合にインデックスが設定されています。
列で圧縮するcscのインデックスは行番号ということになります。
indptr属性
CSCフォーマットのインデックスポインタ配列を表します。
【例】indptrの出力print(csc.indptr)
[0 1 2 5]
indptr解説
indptr(インデックスポインタ)とは下記の図のようなイメージです。
図では矢印がポインタを表しており、それぞれの色と丸印が対応しているポインタの位置を表しています。
ポインタは1列目、2列名、3列目と進んでいきます。

ポインタが青の位置の時(スタート位置の時)、それ以上値が存在しないので個数は0。
ポインタが赤の位置の時、ポインタ位置よりも左にある値は10のみで1個。
ポインタが緑の位置の時、ポインタ位置よりも左にある値は10と30で2個。
ポインタが黒の位置の時、ポインタ位置よりも左にある値は10と30と20と40と50で5個。
つまり、ポインタの位置によってそれぞれの数字をカウントしていることになります。
lil_matrix 行単位リスト
lil(LInked List)は行ごとの情報(値、インデックス)をlistで保持します。
lil_matrix( 配列 )
from scipy.sparse import lil_matrix
ary = [[10, 0, 20],
[0, 30, 40],
[0, 0, 50]]
lil = lil_matrix(ary)
print(lil)
(0, 0) 10
(0, 2) 20
(1, 1) 30
(1, 2) 40
(2, 2) 50
lil_matrix解説
出力形式はcsr_matrixと同様ですが、再掲しておきます。(行,列)を表しています。

出力結果と1行目を照らし合わせると、(0,0) 10, (0,2) 20、二行目は、(1,1) 30,(1,2) 40となり、値がある場所と出力結果が対応しているのが確認できます。
data属性
マトリクスlilフォーマットのデータ配列を表しています。各行の値をlistで保持しています。
【例】dataの出力print(lil.data)
[list([10, 20]) list([30, 40]) list([50])]
結果を見ると、1行目の値10,20がlistで所持され、2行目の値30,40がlistで所持され、という具合になっているのが確認出来ると思います。
rows属性
マトリクスlilフォーマットの行インデックス配列を表します。
【例】rowsの出力print(lil.rows)
[list([0, 2]) list([1, 2]) list([2])]
rows解説
rowsは、行毎のインデックスをlistで保持しています。

図の赤丸と結果を照らし合わせる見ると、1行目が0,2、2行目が1,2、3行目が2、とそれぞれ対応しているのが確認できます。行単位のリストなのでインデックスは何列目かを表しています。
coo_matrix 疎マトリクス
COOrdinate(座標)は座標フォーマットの疎なマトリクスを表します。つまり、行ごとまたは列ごとのインデックスを保持します。
coo_matrix( 配列 )
from scipy.sparse import coo_matrix
ary = [[10, 0, 20],
[0, 30, 40],
[0, 0, 50]]
coo = coo_matrix(ary)
print(coo)
(0, 0) 10
(0, 2) 20
(1, 1) 30
(1, 2) 40
(2, 2) 50
出力結果はcsr_matrixと同様に、(行,列) 値、を表しています。
data属性
マトリクスCOOフォーマットのデータ配列を表します。csr_matrixと同様に値そのものを表しています。
【例】dataの出力print(coo.data)
[10 20 30 40 50]
row属性
マトリクスCOOフォーマットの行インデックス配列を表します。つまり行番号を出力します。
【例】rowの出力print(coo.row)
[0 0 1 1 2]
row解説
row(行)は、下記の図の赤丸で囲った数字を指します。

出力結果と赤丸の数字を照らし合わせてみると、各行番号を表していることが確認できます。
col属性
マトリクスCOOフォーマットの列インデックス配列を表します。つまり列番号を出力します。
【例】colの出力print(coo.col)
[0 2 1 2 2]
col解説
col(列)は、下記の図の赤丸で囲った数字を指します。

出力結果と赤丸の数字を照らし合わせてみると、各列番号を表していることが確認できます。
hstack 水平方向の連結
hstack(horizontal stack)は疎のマトリクス(行列)を水平方向に連結します。
Numpyにもhstackがあります。
hstack([ 配列1, 配列2 ])
from scipy.sparse import coo_matrix, hstack
ary1 = [[10, 0, 20],
[0, 30, 40],
[0, 0, 50]]
ary2 = [[60, 0, 70],
[0, 80, 90],
[0, 0, 100]]
coo1 = coo_matrix(ary1)
coo2 = coo_matrix(ary2)
hs = hstack([coo1,coo2]).toarray()
print(hs)
[[ 10 0 20 60 0 70]
[ 0 30 40 0 80 90]
[ 0 0 50 0 0 100]]
出力結果より、それぞれの配列ary1,ary2の一行目を見てみると、[10,0,20]と[60,0,70]が[10,0,20,60,0,70]と連結されているのが確認できます。