の中にnumpy マニュアルreshape()関数については、
>>> a = np.zeros((10, 2))
# A transpose make the array non-contiguous
>>> b = a.T
# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()
>>> c.shape = (20)
AttributeError: incompatible shape for a non-contiguous array
私の質問は次のとおりです:
- 連続配列と非連続配列とは何ですか?Cの連続メモリブロックに似ていますか?連続メモリブロックとは何ですか?
- これら 2 つにはパフォーマンスの違いがありますか? どちらをいつ使用すればよいですか?
- なぜ転置によって配列が非連続になるのでしょうか?
- なぜ
c.shape = (20)
エラーが発生するのでしょうかincompatible shape for a non-contiguous array
?
ご回答有難うございます!
ベストアンサー1
連続配列とは、メモリの連続ブロックに格納される配列です。配列内の次の値にアクセスするには、次のメモリ アドレスに移動するだけです。
2D 配列を考えてみましょうarr = np.arange(12).reshape(3,4)
。次のようになります。
コンピュータのメモリでは、 の値はarr
次のように保存されます。
これはarr
、C 連続配列は行連続したメモリ ブロックとして保存されます。次のメモリ アドレスには、その行の次の行の値が保持されます。列を下に移動する場合は、3 つのブロックをスキップするだけです (たとえば、0 から 4 にジャンプするには、1、2、3 をスキップします)。
配列を転置すると、arr.T
隣接する行のエントリが隣接するメモリアドレスになくなるため、Cの連続性が失われます。ただしarr.T
、Fortran連続以来列連続したメモリブロック内にあります。
パフォーマンスの点では、互いに隣接しているメモリ アドレスにアクセスする方が、より「分散している」アドレスにアクセスするよりも高速になることがよくあります (RAM から値を取得すると、CPU 用にフェッチされキャッシュされる隣接アドレスが多数必要になる場合があります)。つまり、連続した配列に対する操作は、多くの場合、より高速になります。
Cの連続メモリレイアウトの結果として、行方向の操作は通常、列方向の操作よりも高速です。たとえば、通常、
np.sum(arr, axis=1) # sum the rows
以下よりもわずかに高速です:
np.sum(arr, axis=0) # sum the columns
同様に、Fortran の連続配列では列に対する操作がわずかに高速化されます。
最後に、新しい形状を割り当てることによって Fortran の連続配列を平坦化できないのはなぜでしょうか?
>>> arr2 = arr.T
>>> arr2.shape = 12
AttributeError: incompatible shape for a non-contiguous array
これを可能にするには、NumPy はarr.T
次のように行をまとめる必要があります。
(shape
属性を直接設定すると、C の順序が想定されます。つまり、NumPy は行単位で操作を実行しようとします。)
これは不可能です。どの軸でも、NumPyは絶え間ない配列の次の要素に到達するためのストライド長 (移動するバイト数)。arr.T
この方法でフラット化する場合、配列の連続する値を取得するためにメモリ内を前後にスキップする必要があります。
代わりに次のように記述するとarr2.reshape(12)
、NumPy は arr2 の値を新しいメモリ ブロックにコピーします (この形状の元のデータへのビューを返すことができないため)。