12

scipy.sparse パッケージから lil_matrix (A) をスライスするときの次の動作を理解するために、助けていただければ幸いです。

実際には、行と列の両方の任意のインデックス リストに基づいて部分行列を抽出したいと考えています。

この2行のコードを使用したとき:

x1 = A[list 1,:]
x2 = x1[:,list 2]

すべてが順調で、適切な部分行列を抽出できました。

これを一行でやろうとしたところ、失敗しました(返される行列は空でした)

x=A[list 1,list 2]

これはなぜですか?全体として、私はmatlabで同様のコマンドを使用しましたが、そこで動作します。では、機能するので、最初のものを使用しないのはなぜですか? かなり手間がかかりそうです。大量のエントリを通過する必要があるため、単一のコマンドで高速化したいと考えています。間違った疎行列タイプを使用している可能性があります...何か考えはありますか?

4

4 に答える 4

15

すでにお使いの方法で、

A[list1, :][:, list2]

スペアマトリックスから目的の値を選択する最速の方法のようです。ベンチマークについては、以下を参照してください。

A ただし、単一のインデックスを使用して任意の行と列から値を選択する方法に関する質問に答えるには、いわゆる「高度なインデックス作成」を使用する必要があります。

A[np.array(list1)[:,np.newaxis], np.array(list2)]

高度なインデックス付けでは、arr1arr2が NDarrayの場合、 equalsの(i,j)コンポーネントA[arr1, arr2]

A[arr1[i,j], arr2[i,j]]

したがって、 equal for allと arr1[i,j]equal for all が必要になります。list1[i]jarr2[i,j]list2[j]i

これは、ブロードキャスト(以下を参照) を 使用してarr1 = np.array(list1)[:,np.newaxis]、 とを設定することで調整できますarr2 = np.array(list2)

必要に応じて左側に新しい軸が自動的に追加されるため、 arr1isの形(len(list1), 1)arr2is (len(list2), )which にブロードキャストされます。(1, len(list2))

各配列はさらに shape にブロードキャストできます(len(list1),len(list2))。shape の結果配列のすべての可能なインデックスを実行したいので、これはまさに私たち A[arr1[i,j],arr2[i,j]]が意味を成すために望んでいることです。(i,j)(len(list1),len(list2))


A[list1, :][:, list2]これが最速のオプションであることを示唆する 1 つのテスト ケースのマイクロベンチマークです。

In [32]: %timeit orig(A, list1, list2)
10 loops, best of 3: 110 ms per loop

In [34]: %timeit using_listener(A, list1, list2)
1 loop, best of 3: 1.29 s per loop

In [33]: %timeit using_advanced_indexing(A, list1, list2)
1 loop, best of 3: 1.8 s per loop

ベンチマークに使用したセットアップは次のとおりです。

import numpy as np
import scipy.sparse as sparse
import random
random.seed(1)

def setup(N):
    A = sparse.rand(N, N, .1, format='lil')
    list1 = np.random.choice(N, size=N//10, replace=False).tolist()
    list2 = np.random.choice(N, size=N//20, replace=False).tolist()
    return A, list1, list2

def orig(A, list1, list2):
    return A[list1, :][:, list2]

def using_advanced_indexing(A, list1, list2):
    B = A.tocsc()  # or `.tocsr()`
    B = B[np.array(list1)[:, np.newaxis], np.array(list2)]
    return B

def using_listener(A, list1, list2):
    """https://stackoverflow.com/a/26592783/190597 (listener)"""
    B = A.tocsr()[list1, :].tocsc()[:, list2]
    return B

N = 10000
A, list1, list2 = setup(N)
B = orig(A, list1, list2)
C = using_advanced_indexing(A, list1, list2)
D = using_listener(A, list1, list2)
assert np.allclose(B.toarray(), C.toarray())
assert np.allclose(B.toarray(), D.toarray())
于 2011-09-30T12:23:05.020 に答える
4

私にとっては、unutbu のソリューションはうまく機能しますが、遅いです。

私は速い代替手段として見つけました、

A = B.tocsr()[np.array(list1),:].tocsc()[:,np.array(list2)]

行と列が別々に切り取られていることがわかりますが、今回はインデックスを取得するために、それぞれが最速のスパース形式に変換されています。

私のテスト環境では、このコードは他のコードよりも 1000 倍高速です。

間違ったことを言ったり、間違えたりしないことを願っています。

于 2014-10-27T16:59:03.993 に答える
-1

スライスは次の構文で行われます:

a[1:4]

a = array([1,2,3,4,5,6,7,8,9]) の場合、結果は次のようになります。

array([2, 3, 4])

タプルの最初のパラメーターは保持する最初の値を示し、2 番目のパラメーターは保持しない最初の値を示します。

両側でリストを使用する場合、配列にはリストの長さと同じ数の次元があることを意味します。

したがって、あなたの構文では、おそらく次のようなものが必要になるでしょう:

x = A[list1,:,list2]

Aの形状によります。

それがあなたを助けたことを願っています。

于 2011-09-30T12:15:23.067 に答える