sparse.lil_matrix形式を使用している場合、マトリックスから列を簡単かつ効率的に削除するにはどうすればよいですか?
6 に答える
はるかにシンプルで高速です。csrへの変換も必要ないかもしれませんが、csrのスパース行列で機能し、変換が問題にならないことは確かです。
from scipy import sparse
x_new = sparse.lil_matrix(sparse.csr_matrix(x)[:,col_list])
私はこれを自分で望んでいましたが、実際には、それを行うための優れた組み込みの方法はまだありません。これを行う方法は次のとおりです。lil_matrixのサブクラスを作成し、remove_col関数を追加することを選択しました。必要に応じて、代わりにファイルのlil_matrixクラスにremovecol関数を追加できlib/site-packages/scipy/sparse/lil.py
ます。コードは次のとおりです。
from scipy import sparse
from bisect import bisect_left
class lil2(sparse.lil_matrix):
def removecol(self,j):
if j < 0:
j += self.shape[1]
if j < 0 or j >= self.shape[1]:
raise IndexError('column index out of bounds')
rows = self.rows
data = self.data
for i in xrange(self.shape[0]):
pos = bisect_left(rows[i], j)
if pos == len(rows[i]):
continue
elif rows[i][pos] == j:
rows[i].pop(pos)
data[i].pop(pos)
if pos == len(rows[i]):
continue
for pos2 in xrange(pos,len(rows[i])):
rows[i][pos2] -= 1
self._shape = (self._shape[0],self._shape[1]-1)
試してみましたが、バグはありません。確かに、私が知る限り、新しいマトリックスを作成するだけで、列をスライスするよりも優れていると思います。
removerow関数も作ることにしましたが、removecolほど良くないと思います。ndarrayから希望する方法で1つの行を削除できないという制限があります。上記のクラスに追加できるremoverowは次のとおりです
def removerow(self,i):
if i < 0:
i += self.shape[0]
if i < 0 or i >= self.shape[0]:
raise IndexError('row index out of bounds')
self.rows = numpy.delete(self.rows,i,0)
self.data = numpy.delete(self.data,i,0)
self._shape = (self._shape[0]-1,self.shape[1])
おそらく、これらの関数をScipyリポジトリに送信する必要があります。
スパースcsr行列(X)とドロップするインデックスのリスト(index_to_drop)の場合:
to_keep = list(set(xrange(X.shape[1]))-set(index_to_drop))
new_X = X[:,to_keep]
lil_matricesをcsr_matricesに変換するのは簡単です。lil_matrixドキュメントのtocsr()を確認してください
ただし、tolil()を使用してcsrからlil行列に移行するにはコストがかかることに注意してください。したがって、この選択は、行列をlil形式にする必要がない場合に適しています。
私はPythonを初めて使用するので、答えはおそらく間違っていますが、なぜ次のようなものが効率的でないのか疑問に思いました。
lil_matrixがmatと呼ばれ、i番目の列を削除するとします。
mat=hstack( [ mat[:,0:i] , mat[:,i+1:] ] )
その後、行列はcoo_matrixに変わりますが、lil_matrixに戻すことができます。
わかりました。これは、mat変数への割り当てを行う前に、hstack内に2つの行列を作成する必要があることを理解しています。したがって、元の行列に1つを同時に加えたようなものになりますが、スパース性が十分に大きいかどうかを推測します。そうすれば、メモリの問題はないはずだと思います(メモリ(および時間)がスパース行列を使用する理由全体であるため)。
def removecols(W, col_list):
if min(col_list) = W.shape[1]:
raise IndexError('column index out of bounds')
rows = W.rows
data = W.data
for i in xrange(M.shape[0]):
for j in col_list:
pos = bisect_left(rows[i], j)
if pos == len(rows[i]):
continue
elif rows[i][pos] == j:
rows[i].pop(pos)
data[i].pop(pos)
if pos == len(rows[i]):
continue
for pos2 in xrange(pos,len(rows[i])):
rows[i][pos2] -= 1
W._shape = (W._shape[0], W._shape[1]-len(col_list))
return W
col_listを入力として使用するようにコードを書き直しただけです。これは、誰かに役立つかもしれません。
各スパース行列の注記を見ると、特にこの場合はcsc行列であり、ドキュメント[1]にリストされている次の利点があります。
- 効率的な算術演算CSC+CSC、CSC*CSCなど。
- 効率的なカラムスライス
- 高速行列ベクトル積(CSR、BSRの方が速い場合があります)
削除する列インデックスがある場合は、スライスを使用するだけです。行を削除するには、行のスライスに効率的であるため、csr行列を使用します