100万×100万の行列を作って、機械学習をぶん回して…とやっていると 本当に心配になるくらいmacが熱くなりますし、メモリも食って、計算終わらなくて。。。 ということでスパース表現ですね。
スパース表現とは
行列の要素のほとんどが0、わずかにしか値が入ってないようなとき、 例えばこんなん
array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
0をわざわざデータとして保持するんじゃなくて、 わずかに入る値とその位置だけ保持して、あとは0であるとみなすことで 持っているべき情報量を落とすための表現です。 つまり、上の行列は
row = np.array([0, 3, 1, 0])
col = np.array([0, 3, 1, 2])
data = np.array([4, 5, 7, 9])
みたいに表せます。rowとcolがデータの位置、dataがそこに入る値になってます。 これを
sparse_matrix = coo_matrix((data, (row, col)), shape=(4, 4))
というようにしてスパース行列にします。参考:公式 元の、全ての値を保持する表現はスパースに対してデンス(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/
注意事項
拙作よりもこちらの記事を読んだ方がよいですが http://hamukazu.com/2014/01/30/sparse-vector-with-scipy-sparse/
使うためだけの説明をすると、COOは計算に向かないので、CSRかCSCにします。 CSRは行方向、CSCは列方向の計算を高速化するので、行列の形に応じて使い分けしましょう。
サンプルコード
例えばさきほどのNMFでは
import pandas as pd
import numpy as np
import scipy
from sklearn.decomposition import NMF
def feature_extraction(mat_coo, num_features):
X = mat_coo.tocsr()
model = NMF(n_components=num_features, init='random', random_state=0)
model.fit(X)
print('feature extraction done')
return model.components_
if __name__ == '__main__':
num_features = 3
print('now loading...')
row = np.array([0, 3, 1, 0])
col = np.array([0, 3, 1, 2])
data = np.array([4, 5, 7, 9])
mat_coo = scipy.sparse.coo_matrix((data, (row, col)), shape=(4, 4))
features = feature_extraction(mat_coo, num_features)
みたいな感じでできます。
圧倒的に高速なので、データがスパースな場合にはぜひ活用しましょう。