scipy.sparse

 わたしの専攻は応用数学みたいなもので,特に機械学習なるものを主に研究している*1.純粋に数学をやろうと思うならば,「拙者wwwデッデュフwwwwこのwwンゴォwwてwwwwてwwwwww定理wwwwコポォwwwwww証明したでござるwwwww」と言っていればいいのであるが*2,我々の業界*3ではこんなことばかり言っていても,「それはなんの役に立つんですか?」とボスに聞かれ,ぐぬぬとなってしまうので,それを未然に防ぐために,何か適当なデータを持ってきて,自分のアルゴリズムを試して性能がいいですよ*4ということを言わなければならない.生まれつきC++が書けるとか,脳内で反復法の計算ができるという方ならば,実装の面で悩むことはないのだろうが,私くらいの凡人ともなると極力楽をしたいので,ライブラリなどが揃っていたり,身近な人*5に質問ができるような言語を選んでしまう.そのため私は SciPy/NumPy がある Python を使うことにした.

 機械学習では,スパースなデータというものがよく出てくるのだが,このようなデータを脳味噌スパース野郎が何も考えずに作ったプログラムに食わせるとエライことになってしまうので*6,ちゃんとスパースなデータ構造で持って置かなければならない. SciPy には scipy.sparse というものが存在して,これを使えば脳味噌スパース野郎でもスパースデータを扱える!!!と思いきや,なんかこれよくわからない感じなので,使った限りで機能をメモして残しておきたいと思う.

行列の作り方

 脳味噌スパース野郎「さあ,スパースな行列作っちゃうか!!!」→リファレンスをみる→脳味噌スパース野郎「いっぱい種類があってわからないお....」*7となってしまうので,使ったものの特徴を適当にまとめてみる.簡単に言うと,行列を作るときは coo_matrix やら lil_matrix,行列の演算をするときは csc_matrix やら csr_matrix を使え,ということらしい.

coo_matrix(arg1[, shape, dtype, copy])

長所
  • 行列を作るのが速い
  • csr_matrix や csc_matrix への変換が速い
短所
  • 演算は直接はサポートしていない
>>> A = scipy.sparse.coo_matrix(([1],([0],[1])),shape=(5,5))
>>> A.todense()
matrix([[0, 1, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]])
>>> type(A)
<class 'scipy.sparse.coo.coo_matrix'>
>>> type(A+A)
<class 'scipy.sparse.csr.csr_matrix'>

どうやら演算は csr_matrix に変換して行うようだ.

  • 要素を指定して代入できない
>>> A = scipy.sparse.coo_matrix(([1],([0],[1])),shape=(5,5))
>>> A[0,0]=3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'coo_matrix' object does not support item assignment

こういうことをしたい場合は lil_matrix でやるのがよいらしい.


csc_matrix(arg1[, shape, dtype, copy])

長所
  • csc_matrix どうしの演算が速い
  • 列の切り出しが速い
短所
  • 行の切り出しが遅い(csr_matrix の方が速い)
  • 他のフォーマットに変換するのが遅い(lil_matrix の方が速い)

csr_matrix(arg1[, shape, dtype, copy])

長所
  • csr_matrix どうしの演算が速い
  • 行の切り出しが速い
短所
  • 列の切り出しが遅い(csc_matrix の方が速い)
  • 他のフォーマットに変換するのが遅い(lil_matrix の方が速い)

lil_matrix(arg1[, shape, dtype, copy])

長所

行列を作りやすい.行列のインデックスを指定して要素を代入するのが速くできる.

import scipy as sp
import scipy.sparse

A = sp.sparse.lil_matrix((10,10))
A[0,1] = 10

とやっても怒られない(csr_matrix などでこのようなことをやると,「効率悪いぞ,能なし野郎!!!!」と怒られ,その日一日嫌な気持ちになる).
dok_matrix でも同じようなことができるっぽいし,各要素O(1)でアクセスできると書いてあるので,dok_matrix の方がいいのかもしれないが,よくわからない.

短所

色々遅い.行列の切り出しやら演算やらは csc_matrix や csr_matrix に変換して行うのがいいし,行列を作るのは coo_matrix の方が速いらしい.
csc_matrix, csr_matrix に変換するのは簡単で,

A = A.tocsr()

で一発.


 ここまで書いただけで疲れはててしまったので,これ以降の話はまた今度元気が有り余っているときに書くことにする.