てけノート

on the foot of giants

[python] scikit-learnでメモリに困ったらスパース表現がよい

      2017/03/08


100万×100万の行列を作って、機械学習をぶん回して…とやっていると
本当に心配になるくらいmacが熱くなりますし、メモリも食って、計算終わらなくて。。。
ということでスパース表現ですね。

スパース表現とは

行列の要素のほとんどが0、わずかにしか値が入ってないようなとき、
例えばこんなん

0をわざわざデータとして保持するんじゃなくて、
わずかに入る値とその位置だけ保持して、あとは0であるとみなすことで
持っているべき情報量を落とすための表現です。
つまり、上の行列は

みたいに表せます。rowとcolがデータの位置、dataがそこに入る値になってます。
これを

というようにしてスパース行列にします。参考:公式
元の、全ての値を保持する表現はスパースに対してデンス(dense)と呼ばれます。
こちらの記事が詳しい。

denseの扱いとの違い

基本的にはdenseの場合と同様の処理ができます。
ただ、一般的な結合などもスパース行列用に関数がありますのでそちらを利用します。例:縦方向の結合

scikit-learnと一緒に使う

scikit-learnの多くのアルゴリズムはスパース行列に対応してるので、
今まで普通に行列を引数で渡していたように引数に渡せます。
例えば推薦システムなどに使う非負値行列因子分解(Non-negative Matrix Factorization)のParameterの項を見ると

X: {array-like, sparse matrix}, shape (n_samples, n_features) :
Data matrix to be decomposed

となってるので、sparse matrixを引数に取れるよ、ということですね。
NMFについてはこちらがわかりやすい。
実例はこんな感じ http://www.benfrederickson.com/matrix-factorization/

注意事項

拙作よりもこちらの記事を読んだ方がよいですが

scipy.sparseでの疎ベクトルの扱い

使うためだけの説明をすると、COOは計算に向かないので、CSRかCSCにします。
CSRは行方向、CSCは列方向の計算を高速化するので、行列の形に応じて使い分けしましょう。

サンプルコード

例えばさきほどのNMFでは

みたいな感じでできます。

圧倒的に高速なので、データがスパースな場合にはぜひ活用しましょう。

 - プログラミング, 機械学習