2016-05-31 8 views
0

以下の最小限の例を考えてみましょう。さまざまな入れ子の深さのリスト要素をコピーすることについて、誰かが明らかに矛盾した論理numpyを説明できますか?numpyの配列をコピーするときの動作が一貫していないようです。

import numpy as np 

L = [[[[1, 1], 2, 3]]] 
A1 = np.array(L) 

A2 = A1.copy() 

A1[0][0][2] = 'xx' 
A1[0][0][0][0] = 'yy' 

print "\nA1 after changes:\n{}".format(A1) 
print "\nA2 only partially changed:\n{}".format(A2) 

結果:

A1 after changes: 
[[[['yy', 1] 2 'xx']]] 

A2 only partially changed: 
[[[['yy', 1] 2 3]]] 

その後:

>>> print A1[0][0][2] == A2[0][0][2] 
False 
>>> print A1[0][0][0][0] == A2[0][0][0][0] 
True 

私は3が交換されていない理由を自分自身に説明する苦労を持っていますが、より深いレベルでの1です。

  1. A2 = np.array(A, copy=True)A2 = np.empty_like(A); np.copyto(A4, A)

  2. A2 = A[:]上記のコードはA2 = Aと同じ振る舞いと同じように振る舞う:両方が同一で変化

  3. import copy; A2 = copy.deepcopy(A)私は独立して作成することが見出さ唯一の解決策であり、後コピー。

+0

深いコピーだけがこれを止めることが分かったとすれば、あなたを混乱させる原因は何ですか?他のケースでは、*同じ参照可能なオブジェクトへの参照をコピーしています*。 – jonrsharpe

+1

これは 'dtype = object'という配列を持っているからです...基本的には、Pythonリストと2つのPython整数への参照を保持する配列を持っています。配列をコピーすると、単に参照がコピーされます。 – mgilson

+0

私は重複が気に入らない。ナンシーアレイには特別なコピーの問題があります。また、 'dtype'オブジェクト配列はこの問題をさらに複雑にします。この質問を再開する必要があります。 – hpaulj

答えて

1

あなたの配列を見て、最初にその構造を理解する:

In [139]: A1 
Out[139]: array([[[[1, 1], 2, 3]]], dtype=object) 

In [140]: A1.shape 
Out[140]: (1, 1, 3) 

それはdtype=object配列です。つまり、要素はオブジェクトポインタであり、数値ではありません。また、それは3つの要素を持つ3dです。

In [142]: A1[0,0] 
Out[142]: array([[1, 1], 2, 3], dtype=object) 

それは配列であるため、A1[0,0]A1[0][0]よりも優れています。機能的には同じですが、より明確です。 A1[0,0,:]はさらに優れています。とにかく、このレベルではまだ形状が(3,)の配列を持っています。つまり3d要素の1dです。

In [143]: A1[0,0,0] 
Out[143]: [1, 1] 

In [144]: A1[0,0,2] 
Out[144]: 3 

ここでは、リストと数字、個々の要素はA1です。リストは変更可能ですが、番号は変更できません。

私たちは、文字列に第三の要素(番号)を変更することができます。

In [148]: A1[0,0,2]='xy' 

が第一の要素、リストの要素を変更するには、私は混合のインデックスを使用する必要がなく、4レベルの配列インデックス作成。

In [149]: A1[0,0,0,0] 
... 
IndexError: too many indices for array 

In [150]: A1[0,0,0][0]='yy' 

In [151]: A1 
Out[151]: array([[[['yy', 1], 2, 'xy']]], dtype=object) 

A1はまだ3Dオブジェクト配列です。いくつかの要素を変更するだけです。 'xy'の変更は 'yy'の変更とは異なります。 1つは配列を変更し、もう1つは配列のリスト要素です。

A2=A1.copy()は、要素のコピー(データバッファ)がA1である新しい配列を作成します。したがって、A2は、A1と同じオブジェクトへのポインタを持っています。

'xy'はポインタをA1に変更しましたが、A2コピーは変更しませんでした。

'yy'変更により、A1が指すリストが変更されました。 A2には同じリストへのポインタがあるため、変更が表示されます。

Lことを、オリジナルのネストされたリストは、同じ変更を見ている:

In [152]: L 
Out[152]: [[[['yy', 1], 2, 3]]] 

A3 = A[:]A1viewを生成します。 A3A1と同じデータバッファを持っているので、すべての変更が表示されます。

A4 = Aも同じ変更が反映されますが、A4はビューまたはコピーではなくA1の新しい参照です。

先に提起されたduplicate answerは、リストの参照、コピー、および深いコピーを取り扱った。これは、Lがリストであり、A1がオブジェクト配列であり、多くの点ではリストを囲む配列ラッパーであるため、ここでは関係します。しかし、A1もnumpy配列であり、viewcopyの間に追加の区別があります。

これはnumpyアレイの有効な使用ではなく、オブジェクトdtypeバージョンでもありません。これは有益な例ですが、実用的すぎるほど混乱しています。配列上にdeepcopyを実行する必要がある場合は、配列を間違って使用している可能性があります。

関連する問題