web-dev-qa-db-ja.com

numpy配列から一度に複数のスライスを選択する

Numpy配列から複数のスライスを一度に選択する方法を探しています。 1Dデータ配列があり、その3つの部分を以下のように抽出したいとします。

data_extractions = []

for start_index in range(0, 3):
    data_extractions.append(data[start_index: start_index + 5])

その後data_extractionsは次のようになります:

data_extractions = [
    data[0:5],
    data[1:6],
    data[2:7]
]

Forループなしで上記の操作を実行する方法はありますか?配列から複数のスライスを選択してそれらをその数の配列として返すことができる、numpyのある種のインデックススキーマ(n + 1次元配列など)


データを複製して各行からスパンを選択できると思いましたが、以下のコードはIndexErrorをスローします

replicated_data = np.vstack([data] * 3)
data_extractions = replicated_data[[range(3)], [slice(0, 5), slice(1, 6), slice(2, 7)]
16
Puchatek

インデックスを使用して、適切な形状にする行を選択できます。例えば:

 data = np.random.normal(size=(100,2,2,2))

 # Creating an array of row-indexes
 indexes = np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
 # data[indexes] will return an element of shape (3,5,2,2,2). Converting
 # to list happens along axis 0
 data_extractions = list(data[indexes])

 np.all(data_extractions[1] == s[1:6])
 True
5
tmrlvi

この投稿には、基本的に入力配列にビューを作成するstrided-indexing schemeを使用したアプローチがあります np.lib.stride_tricks.as_strided これは、ビューを作成するのに非常に効率的で、ビューがメモリスペースを占有しないためです。 。また、これは一般的な次元数を持つndarrayに対して機能します。

ここに実装があります-

def strided_axis0(a, L):
    # Store the shape and strides info
    shp = a.shape
    s  = a.strides

    # Compute length of output array along the first axis
    nd0 = shp[0]-L+1

    # Setup shape and strides for use with np.lib.stride_tricks.as_strided
    # and get (n+1) dim output array
    shp_in = (nd0,L)+shp[1:]
    strd_in = (s[0],) + s
    return np.lib.stride_tricks.as_strided(a, shape=shp_in, strides=strd_in)

4D配列の場合のサンプル実行-

In [44]: a = np.random.randint(11,99,(10,4,2,3)) # Array

In [45]: L = 5      # Window length along the first axis

In [46]: out = strided_axis0(a, L)

In [47]: np.allclose(a[0:L], out[0])  # Verify outputs
Out[47]: True

In [48]: np.allclose(a[1:L+1], out[1])
Out[48]: True

In [49]: np.allclose(a[2:L+2], out[2])
Out[49]: True
6
Divakar

stride_tricksできる

a = np.arange(10)
b = np.lib.stride_tricks.as_strided(a, (3, 5), 2 * a.strides)
b
# array([[0, 1, 2, 3, 4],
#        [1, 2, 3, 4, 5],
#        [2, 3, 4, 5, 6]])

bは実際にはaと同じメモリを参照することに注意してください(たとえば、b[0, 1]およびb[1, 0]は同じメモリアドレスです)。したがって、新しい構造で作業する前にコピーを作成するのが最も安全です。

ndは、2d-> 4dのように、同様の方法で実行できます。

a = np.arange(16).reshape(4, 4)
b = np.lib.stride_tricks.as_strided(a, (3,3,2,2), 2*a.strides)
b.reshape(9,2,2) # this forces a copy
# array([[[ 0,  1],
#         [ 4,  5]],

#        [[ 1,  2],
#         [ 5,  6]],

#        [[ 2,  3],
#         [ 6,  7]],

#        [[ 4,  5],
#         [ 8,  9]],

#        [[ 5,  6],
#         [ 9, 10]],

#        [[ 6,  7],
#         [10, 11]],

#        [[ 8,  9],
#         [12, 13]],

#        [[ 9, 10],
#         [13, 14]],

#        [[10, 11],
#         [14, 15]]])
4
Paul Panzer

準備したスライスアレイでアレイをスライスできます

a = np.array(list('abcdefg'))

b = np.array([
        [0, 1, 2, 3, 4],
        [1, 2, 3, 4, 5],
        [2, 3, 4, 5, 6]
    ])

a[b]

ただし、bはこの方法で手動で生成する必要はありません。それはよりダイナミックにすることができます

b = np.arange(5) + np.arange(3)[:, None]
3
piRSquared

一般的なケースでは、インデックスを構築するとき、または結果を収集するときに、何らかの反復と連結を行う必要があります。 as_stridedを介して一般化されたスライスを使用できるのは、スライスパターン自体が規則的である場合のみです。

受け入れられた答えは、スライスごとに1行のインデックス配列を構築します。つまり、これはスライスを反復処理することであり、arange自体は(高速)反復です。そしてnp.arrayはそれらを新しい軸に連結します(np.stackはこれを一般化します)。

In [264]: np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
Out[264]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

indexing_tricks同じことを行うための便利なメソッド:

In [265]: np.r_[0:5, 1:6, 2:7]
Out[265]: array([0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6])

これはスライス表記を取り、arangeで展開して連結します。 2Dに展開して連結することもできます

In [269]: np.r_['0,2',0:5, 1:6, 2:7]
Out[269]: 
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

In [270]: data=np.array(list('abcdefghijk'))
In [272]: data[np.r_['0,2',0:5, 1:6, 2:7]]
Out[272]: 
array([['a', 'b', 'c', 'd', 'e'],
       ['b', 'c', 'd', 'e', 'f'],
       ['c', 'd', 'e', 'f', 'g']], 
      dtype='<U1')
In [273]: data[np.r_[0:5, 1:6, 2:7]]
Out[273]: 
array(['a', 'b', 'c', 'd', 'e', 'b', 'c', 'd', 'e', 'f', 'c', 'd', 'e',
       'f', 'g'], 
      dtype='<U1')

インデックス作成後の結果の連結も機能します。

In [274]: np.stack([data[0:5],data[1:6],data[2:7]])

他のSO=質問からの私の記憶は、相対的なタイミングが同じ大きさであるということです。それは、たとえば、スライスの数とその長さによって異なる場合があります。全体として必要な値の数ソースからターゲットにコピーされたものは同じになります。

スライスの長さが異なる場合は、フラットインデックスを使用する必要があります。

1
hpaulj

これにはリスト内包表記を使用できます

data=np.array([1,2,3,4,5,6,7,8,9,10])
data_extractions=[data[b:b+5] for b in [1,2,3,4,5]]
data_extractions

結果

[array([2, 3, 4, 5, 6]), array([3, 4, 5, 6, 7]), array([4, 5, 6, 7, 8]), array([5, 6, 7, 8, 9]), array([ 6,  7,  8,  9, 10])]
0
Anant Gupta