2017-03-06 4 views
1

私はここに質問がnumpyの中リシェイプ関数は元の配列のあらゆる変更がビューオブジェクトまたは主要なオブジェクトで発生した場合のビューを返すということですコードPythonのnumpyのメモリレイアウト

import numpy as np 
a = np.zeros((3,2)) 
b = a.T.reshape(3*2) 
b[0] = 99 
a 
array([[0,0], 
     [0,0], 
     [0,0]]) 

を実行しようとしています眺望と主題全体に伝わるだろう。

しかし、上記の場合、それは起こっていません。説明してください。

答えて

1

official documentはあなたの質問に対する答えを示します。

可能であれば、これは新しいビューオブジェクトになります。それ以外の場合はコピーになります。返される配列のメモリレイアウト(CまたはFortran連続)の保証はありません。

+0

、それはそれのビューを作成した場合、その後np.may_share_memoryはtrueを返す必要がありますが、私の質問の場合、それは私が知っている理由があればいけない偽を返します(3,2)u write(3,2)の場合には、(3 * 2)のような書き換えの代わりに、reshape関数で、np.may_share_memory関数がtrueを返します。私は確信していませんが、それは私が推測することですそれは私が推測するそれのコピーを作る3 * 2に関連する何かがあります。 – Mayank

2

あなたがやっている最後のリシェイプは、元のメモリレイアウトに進歩で表現することはできません。

orig     1 2 3 4 5 6 ok, strides 2, 1 

transpose    1 3 5 2 4 6 ok, strides 1, 2 

reshaped transpose 1 3 5 2 4 6 impossible 

私はより正確には、これを正しく理解して(または100%わからないんだけど、I私はほぼ100%確信していますが)、コピーが書き戻されたときにはobscure casesがあるかもしれません。いずれにせよ、これはそれらの一つではありません。 reshapeドキュメントから

+0

= np.array([[1,2]、[3,4]、[4、 5]) は、次いでATは 配列を与える([1、3、4]、 [2、4、5]) 、次いで aTreshape(3,2)が得られる アレイ([1、3 ]、 [4,2] [4,5]]) これはなぜ起こるのかわかりません – Mayank

+0

私が書いた数値は値を参照するのではなく、メモリを参照しています場所。メモリは線形であり、多次元配列はすべて1dのメモリアドレスセットにラベリングされます。それをすべての次元が管理できるようにするには_stride_が必要です。配列のセル(2,4)は、メモリ位置array_base + stride0x2 + stride1x4にある。新しい配列は、通常、C連続である。すなわち、最後のストライドは1であり、最後の1つの形状[-1] tranpose stride0とstride1を交換する。 1d配列にはストライド0しかありません。回路図は、元のレイアウトが平坦な転置に対応していない理由を示しています。 –

1

あなたは、インデックスの同じ種類を使用して、新しい配列にraveled配列からの要素を挿入し、最初のほつれとして配列(指定されたインデックスの順序を使用して)再形成と考えることができ

ラベリングのために使用されたように注文してください。

transposeはビューですが、形状、ストライド、および順序が変更されています。行全体ではなく列を下げることによって、元の順序で要素を取得します。しかし、今度は、Cを順番にトランスポーズしてみてください。要素はシャッフルされます。元の1 2 3 4 5 6 ...になる1 4 7 2 5 8 3 ...コピーせずにその注文を得ることはできません。

In [48]: a=np.arange(1,7).reshape(3,2) 
In [49]: a 
Out[49]: 
array([[1, 2], 
     [3, 4], 
     [5, 6]]) 

arange[1,2,3....]を生成した。そのデータバッファはまだaで使用されており、行全体を読み取ることで '回復'できます。

In [50]: b = a.T 
In [51]: b 
Out[51]: 
array([[1, 3, 5], 
     [2, 4, 6]]) 

トランスポーズは、形状、ストライド、および順序を変更することによって生成されます。今はorder = 'F'です。 (私は.flags.__array_interface__でこれを示すことができる。これは、ビューだし、まだ元のarange値を共有しています。今だけ、なぜなら進歩と秩序の、あなたが列を下に読み。

In [52]: c = b.reshape(3,2) 
In [53]: c 
Out[53]: 
array([[1, 3], 
     [5, 2], 
     [4, 6]]) 

これは、同じ形状を有し、進歩、そして「C」aとしてオーダー。しかし、データバッファ元[1,3,5,2..]の並べ替えコピーである。それはあなたが行全体で読み取ることにより、bから取得したいのと同じ順序です。


見て別の方法並べ替え時にcにある元の要素の順序1,2,3をトレースします。

[0,0],[1,1],[0,1],[2,0],[1,0],[2,1] 

または2つのインデックスリストと:

In [57]: a[[0,0,1,1,2,2],[0,1,0,1,0,1]] # regular pattern 
Out[57]: array([1, 2, 3, 4, 5, 6]) 
In [58]: b[[0,1,0,1,0,1],[0,0,1,1,2,2]] # same, switch order 
Out[58]: array([1, 2, 3, 4, 5, 6]) 
In [59]: c[[0,1,0,2,1,2],[0,1,1,0,0,1]] # a jumble 
Out[59]: array([1, 2, 3, 4, 5, 6]) 
+0

私は完全にその転置メモリスペースを共有することに同意します。 aはbとメモリを共有しますが、bはcとスペースを共有しません。 – Mayank

+0

「a」、「b」、「c」の2次元表示では、1,2,3 ...をトレースします。単純なジグザグパターンの2つで、しかし、 'c'では、対角線上、上、二重対角線などです。' numpy'は、元の1,2,3から 'c'を生成するためにストライドと形状を使うことはできません。 – hpaulj

+0

Cが別々のメモリ..右OK! – Mayank