疎行列の使い方について
概要
- メモリ効率が良いデータの保存形態
- 特定のindexに値を保存するのでメモリ効率がよい
- ユースケースとしてNLPやレコメンドなど
pythonでの利用
scipy.sparse
ライブラリを用いる- 疎行列の作成の方法で速度に大きく差がある
インターフェース
初期化
import scipy.sparse as sparse
X = sparse.csr_matrix((values, (iindexes, jindexes)), shape=(height, width), dtype=dtype)
values: List[float, ...]
- (i, j)のインデックスに入る値
iindexes: List[int, ...]
- i番目のインデックス
jindexes: List[int, ...]
- j番目のインデックス
shape: Tuple[int, int]
- 構築する疎行列の(height, width)
dtype: Callable
- int, floatなど
密行列に変換
np.matrix型
が得られる(np.array型
ではないので注意)
dense_x: np.matrix = X.todense()
dense_arr: np.ndarray = np.asarray(dense_x)
具体例
初期化の方法での速度の違い
import pandas as pd
import numpy as np
import scipy.sparse as sparse
import random
from tqdm.auto import tqdm
df = pd.DataFrame()
df["user"] = [random.randint(0, 10) for x in range(10**5)]
df["item"] = [random.randint(0, 5) for x in range(10**5)]
# コンストラクタにseriesと対応する値を入れる方法(早い)
# Wall time: 67 ms
%%time
user_items = sparse.csr_matrix(([1]*len(df), (df["user"], df["item"])))
display(user_items.todense())
# ループを回す方法(遅い)
# Wall time: 10.5 s
%%time
user_items2 = sparse.csr_matrix((df["user"].max()+1, df["item"].max()+1))
for user, item in tqdm(zip(df["user"], df["item"]), total=len(df)):
user_items2[user, item] += 1
display(user_items2.todense())