11

多次元のNumpy配列を使用しています。他のインデックス配列を使用してこれらの配列にアクセスすると、動作に一貫性がないことに気付きました。例えば:

import numpy as np
start = np.zeros((7,5,3))
a     = start[:,:,np.arange(2)]
b     = start[0,:,np.arange(2)]
c     = start[0,:,:2]
print 'a:', a.shape
print 'b:', b.shape
print 'c:', c.shape

この例では、次の結果が得られます。

a: (7, 5, 2)
b: (2, 5)
c: (5, 2)

これは私を混乱させます。「b」と「c」の寸法が同じでないのはなぜですか?「b」が軸の順序を入れ替えるのに、「a」は入れ替えないのはなぜですか?

たくさんの単体テストのおかげで、これらの不整合を中心にコードを設計することができましたが、何が起こっているのかを理解していただければ幸いです。

参考までに、MacPorts経由でPython2.7.3とNumpy1.6.2を使用しています。

4

1 に答える 1

12

構文的には、これは矛盾しているように見えますが、意味的には、ここでは2つの非常に異なることを行っています。aとの定義では、データのコピーを返す高度なインデックス作成(ファンシーインデックス作成と呼ばれることもありbます)を実行しています。の定義では、データのビューを返す基本的なスライスを実行しています。c

違いを理解するには、インデックスがPythonオブジェクトにどのように渡されるかを理解するのに役立ちます。ここではいくつかの例を示します。

>>> class ShowIndex(object):
...     def __getitem__(self, index):
...         print index
... 
>>> ShowIndex()[:,:]
(slice(None, None, None), slice(None, None, None))
>>> ShowIndex()[...,:]
(Ellipsis, slice(None, None, None))
>>> ShowIndex()[0:5:2,::-1]
(slice(0, 5, 2), slice(None, None, -1))
>>> ShowIndex()[0:5:2,np.arange(3)]
(slice(0, 5, 2), array([0, 1, 2]))
>>> ShowIndex()[0:5:2]
slice(0, 5, 2)
>>> ShowIndex()[5, 5]
(5, 5)
>>> ShowIndex()[5]
5
>>> ShowIndex()[np.arange(3)]
[0 1 2]

ご覧のとおり、さまざまな構成が考えられます。まず、個々のアイテムを渡すか、アイテムのタプルを渡すことができます。次に、タプルには、sliceオブジェクト、Ellipsisオブジェクト、プレーン整数、またはnumpy配列が含まれる場合があります。

基本的なスライスは、、、、またはオブジェクト、または(と同じ)などのオブジェクトのみを渡すとアクティブになります。これらは、単独またはタプルで渡すことができます。基本的なスライスがどのようにアクティブ化されるかについて、ドキュメントは次のように述べています。intsliceEllipsisNonenumpy.newaxis

基本的なスライスは、objがスライスオブジェクト(括弧内のstart:stop:step表記で構成されている)、整数、またはスライスオブジェクトと整数のタプルである場合に発生します。Ellipsisオブジェクトとnewaxisオブジェクトもこれらに散在させることができます。Numericでの一般的な使用法との下位互換性を維持するために、選択オブジェクトがスライスオブジェクト、Ellipsisオブジェクト、またはnewaxisオブジェクトを含むが、整数配列などを含まないシーケンス(リストなど)の場合も、基本的なスライスが開始されます。埋め込まれたシーケンス。

numpy高度なインデックス作成は、配列、整数のみを含む、または任意の種類のサブシーケンスを含む非タプルシーケンス、または配列またはサブシーケンスを含むタプルを渡すとアクティブになります。

高度なインデックス作成と基本的なスライスの違いの詳細については、ドキュメント(上記にリンク)を参照してください。しかし、この特定のケースでは、何が起こっているのかは私には明らかです。部分インデックスを使用する場合は、次の動作と関係があります。

部分索引付けの規則は、結果の形状(または設定で使用されるオブジェクトの解釈された形状)が、索引付けされた部分空間がブロードキャストされた索引付け部分空間に置き換えられたxの形状であるということです。インデックスサブスペースが互いに隣接している場合、ブロードキャストされたインデックススペースは、x内のすべてのインデックスサブスペースを直接置き換えます。インデックスサブスペースが(スライスオブジェクトによって)分離されている場合、ブロードキャストされたインデックススペースが最初になり、次にxのスライスされたサブスペースが続きます。

a高度なインデックスを使用するの定義では、シーケンス[0, 1]をタプルの3番目の項目として効果的に渡します。また、ブロードキャストが行われないため(他のシーケンスがないため)、すべてが期待どおりに行われます。

の定義ではb、これも高度なインデックスを使用して、最初の項目(配列に変換される)と3番目の項目の2つのシーケンスを効果的に渡します。この2つのアイテムは一緒に放送され、結果は3番目のアイテムと同じ形になります。ただし、ブロードキャストが行われたため、問題が発生しました。新しいシェイプのタプルのどこにブロードキャストされたシェイプを挿入するのでしょうか。ドキュメントが言うように、[0]intp[0, 1]

インデックスサブスペースにドロップする明確な場所がないため、最初に追加されます。

したがって、2ブロードキャストから生じる結果は、シェイプタプルの先頭に移動され、見かけの転置が生成されます。

于 2012-08-13T23:07:33.000 に答える