1

次の点を考慮してください。

import numpy as np

arr = np.arange(3 * 4 * 5).reshape((3, 4, 5))

sarrを使用してスライスすると、次のようになります。slice

arr[:, 0:2, :].shape
# (3, 2, 5)

arrとの混合物を使用してスライスするslice()tuple()、次のようになります。

arr[:, (0, 1), :].shape
# (3, 2, 5)

np.all(arr[:, (0, 1), :] == arr[:, :2, :])
# True

と:

arr[:, :, (0, 1)].shape
# (3, 4, 2)

np.all(arr[:, :, (0, 1)] == arr[:, :, :2])
# True

ただし、もしそうなら:

arr[:, (0, 1), (0, 1)].shape
# (3, 2)

これは基本的にarr[:, 0, 0]連結arr[:, 1, 1]されています。

私は得ることを期待していました:

arr[:, (0, 1), (0, 1)].shape
# (3, 2, 2)

np.all(arr[:, (0, 1), (0, 1)] == arr[:, :2, :2])
# True

しかし、そうではないことは明らかです。

2 つの個別のスライスを連結すると、目的の結果を得ることができます。つまり、次のようになります。

arr[:, (0, 1), :][:, :, (0, 1)].shape
# (3, 2, 2)

np.all(arr[:, (0, 1), :][:, :, (0, 1)] == arr[:, :2, :2])
# True

単一のスライスarr[:, (0, 1), :][:, :, (0, 1)]を使用しても同じ結果を得ることができますか?

さて、この例はあまり興味深いものではありません。なぜなら、 を に置き換えることができるからtuple()ですslice()

arr[:, (0, 2, 3), :][:, :, (0, 2, 3, 4)]
# [[[ 0  2  3  4]
#   [10 12 13 14]
#   [15 17 18 19]]

#  [[20 22 23 24]
#   [30 32 33 34]
#   [35 37 38 39]]

#  [[40 42 43 44]
#   [50 52 53 54]
#   [55 57 58 59]]]

これarr[:, (0, 2, 3), (0, 2, 3, 4)]は、はるかに便利な構文になります。

編集

@Divakar @hpaulj および @MadPhysicist のコメント/回答は、適切にブロードキャストされた Iterable が複数の連結されたスライスと同等であることを示しました。

ただし、これは当てはまりません。たとえば、次のようになります。

s = np.ix_((0, 1), (0, 1, 2, 3))
arr[s[0], slice(3), s[1]]
# [[[ 0  5 10]
#   [ 1  6 11]
#   [ 2  7 12]
#   [ 3  8 13]]
# 
#  [[20 25 30]
#   [21 26 31]
#   [22 27 32]
#   [23 28 33]]]

しかし:

arr[(0, 1), :, :][:, :3, :][:, :, (0, 1, 2, 3)]
# [[[ 0  1  2  3]
#   [ 5  6  7  8]
#   [10 11 12 13]]
# 
#  [[20 21 22 23]
#   [25 26 27 28]
#   [30 31 32 33]]]

と:

np.all(arr[:2, :3, :4] == arr[(0, 1), :, :][:, :3, :][:, :, (0, 1, 2, 3)])
# True

np.all(arr[s[0], slice(3), s[1]] == arr[(0, 1), :, :][:, :3, :][:, :, (0, 1, 2, 3)])
# False
4

2 に答える 2

1

ix_タプル連結を介してスライスと組み合わせることができます。

In [568]: arr[(slice(None),)+np.ix_((0,2,3),(0,2,3,4))]                                               
Out[568]: 
array([[[ 0,  2,  3,  4],
        [10, 12, 13, 14],
        [15, 17, 18, 19]],

       [[20, 22, 23, 24],
        [30, 32, 33, 34],
        [35, 37, 38, 39]],

       [[40, 42, 43, 44],
        [50, 52, 53, 54],
        [55, 57, 58, 59]]])

ix_タプル:

In [569]: np.ix_((0,2,3),(0,2,3,4))                                                                   
Out[569]: 
(array([[0],
        [2],
        [3]]), array([[0, 2, 3, 4]]))

タプル連結:

In [570]: (slice(None),)+np.ix_((0,2,3),(0,2,3,4))                                                    
Out[570]: 
(slice(None, None, None), array([[0],
        [2],
        [3]]), array([[0, 2, 3, 4]]))
In [571]: arr[_]                                                                                      
Out[571]: 
array([[[ 0,  2,  3,  4],
        [10, 12, 13, 14],
        [15, 17, 18, 19]],
        ....

Python コードでタプルを構築し、それをインデックス式で使用するという考え方は、多くのnumpy関数で使用されています。

このインデックス タプルを構築する別の方法は次のとおりです。

In [581]: arr[(slice(None), *np.ix_((0,2,3),(0,2,3,4)))]                                              
Out[581]: 
array([[[ 0,  2,  3,  4],
        [10, 12, 13, 14],
        [15, 17, 18, 19]],
       ...

これは、タプル内での Python '*' アンパックを利用します (ただし、インデックス式内で直接ではありません)。

これは事実上arr[:,*ix_[...]]、構文エラーを生成する方法です。

要約すると:

  • numpyPython 内で動作するため、すべての構文規則に従う

  • numpy「要素」の索引付けを容易にします。ブロックのインデックス作成は少し難しくなりますが、実際には同じbroadcastingルールに従います。

  • MATLAB には独自の言語と構文があります。これにより、ブロックのインデックス付けが簡単になりますが、対角線を取得するなどの要素のインデックス付けはより扱いにくく、追加のsub2ind関数呼び出しが必要になります。

于 2019-05-27T21:02:58.937 に答える