はじめに
疎行列はメモリ消費こそ少ないものの、scikit-learnで使うと内部でnumpy配列に変換されたりしてあまり恩恵を受けられないことが多いです。
でも、変数選択に使うときはどうやら効くっぽいです。
実験
淡々とやりましょう。20newsgroups+SelectKBestという組み合わせです。
import time import warnings import numpy as np from sklearn.datasets import fetch_20newsgroups_vectorized from sklearn.feature_selection import SelectKBest # サンプリングすると全行0の列がでて警告出るので warnings.filterwarnings("ignore") def main(): # 読み込み。デフォルトでcsr_matrix news20 = fetch_20newsgroups_vectorized( subset="all", remove=("headers", "footers", "quotes")) skb = SelectKBest(k=5000) # ランダムサンプリング idx = np.random.choice(news20.data.shape[0], 2000, replace=False) y = news20.target[idx] data = news20.data[idx] # 疎行列型 print(type(data)) t1 = time.time() res = skb.fit_transform(data, y) t2 = time.time() print("{:.2f}".format(t2 - t1)) print(res.shape) p1 = skb.pvalues_ # numpy配列 data = data.toarray() print(type(data)) t1 = time.time() res = skb.fit_transform(data, y) t2 = time.time() print("{:.2f}".format(t2 - t1)) print(res.shape) p2 = skb.pvalues_ # nanを含むとこう比較しないとだめなはず print(np.allclose(p1, p2, equal_nan=True)) if __name__ == "__main__": main()
結果
<class 'scipy.sparse.csr.csr_matrix'> 0.35 (2000, 5000) <class 'numpy.ndarray'> 2.94 (2000, 5000) True
10倍の速度差がありますね。
サンプル数を増やしてもcsr_matrixの方は同じような時間でやれている雰囲気があり、実際は更に効率的です。ちなみに、全サンプルだとcsr_matrixの方はいけますが、numpy配列の方は何十秒も粘った後にMemoryErrorで落ちました。
結論
スパースな配列を疎行列型にしていたら、そのまま変数選択に渡すべき。ndarrayでやると、とても問題があります。