2016-05-31 23 views
0

Betrachten Sie das folgende minimale Beispiel. Kann jemand die scheinbar inkonsistente Logik von numpy erklären, wenn es darum geht, Listenelemente mit unterschiedlichen Schachtelungstiefen zu kopieren?Anscheinend inkonsistentes Verhalten beim Kopieren von nupy Arrays

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) 

Ergebnisse:

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

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

Dann:

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

Ich habe eine harte Zeit für mich zu erklären, warum 3 nicht ersetzt wird, sondern 1 in einer tieferen Ebene ist.

  1. A2 = np.array(A, copy=True) und A2 = np.empty_like(A); np.copyto(A4, A) verhalten sich genauso wie der Code oben

  2. A2 = A[:] verhält sich genauso wie A2 = A: beide identisch sind, nachdem Änderungen

  3. import copy; A2 = copy.deepcopy(A) die einzige Lösung, die ich eine unabhängige schaffen gefunden Kopieren.

+0

Da Sie herausgefunden haben, dass nur eine tiefe Kopie dies verhindert, was verwirren Sie? In den anderen Fällen kopieren Sie * Verweise auf dasselbe veränderbare Objekt *. – jonrsharpe

+1

Es ist, weil Sie ein Array mit 'dtype = object' haben ... Grundsätzlich haben Sie ein Array, das einen Verweis auf eine Python-Liste und 2 Python-Ganzzahlen enthält. Wenn Sie das Array kopieren, kopiert es nur die Referenzen. – mgilson

+0

Ich mag das Duplikat nicht. Numpy-Arrays haben spezielle Kopierprobleme. Und 'dtype' Objekt-Arrays komplizieren das Problem weiter. Diese Frage sollte erneut geöffnet werden. – hpaulj

Antwort

1

Blick auf das Array, und seine Struktur zuerst verstehen:

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

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

Es ist ein dtype=object Array; das sind die Elemente sind Objektzeiger, keine Zahlen. Auch es ist 3d, mit 3 Elementen.

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

Da es ein Array ist, ist besser als A1[0,0]A1[0][0]. Funktional gleich, aber klarer. A1[0,0,:] ist noch besser. Wie auch immer, auf dieser Ebene haben wir immer noch ein Array mit der Form (3,), d.h. 1d mit 3 Elementen.

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

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

Jetzt bekommen wir eine Liste und Zahlen, die einzelnen Elemente A1. Die Liste ist änderbar, die Nummer nicht.

Wir können das dritte Element ändern (eine Zahl) in einen String:

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

Um ein Element des ersten Elements zu ändern, eine Liste, ich habe die gemischte Indizierung verwenden, keine 4-Level-Array Indizierung.

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 ist immer noch eine 3D-Objektarray; Wir haben nur ein paar Elemente geändert. Die 'xy' Änderung unterscheidet sich von der 'yy' Änderung. Einer hat das Array geändert, der andere ein Listenelement des Arrays.

A2=A1.copy() erstellt ein neues Array mit Kopien der Elemente (der Datenpuffer) von A1. So hat A2 Zeiger auf die gleichen Objekte wie A1.

Die 'xy' hat den Zeiger in A1 geändert, aber die A2 Kopie nicht geändert.

Die Änderung 'yy' änderte die Liste, auf die A1 zeigt. A2 hat einen Zeiger auf die gleiche Liste, so dass es die Änderung sieht.

Beachten Sie, dass L, sieht die ursprüngliche verschachtelte Liste die gleiche Änderung:

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

A3 = A[:] erzeugt eine view von A1. A3 hat den gleichen Datenpuffer wie A1, so sieht es alle Änderungen.

A4 = A würde auch die gleichen Änderungen sehen, aber A4 ist eine neue Referenz auf A1, keine Ansicht oder eine Kopie.

Die duplicate answer, die früher angesprochen wurde, behandelt Referenzen, Kopien und tiefe Kopien von Listen. Das ist hier relevant, weil L eine Liste ist und A1 ein Objekt-Array ist, das in vielerlei Hinsicht ein Array-Wrapper um eine Liste ist. Aber A1 ist auch Numy Array, die die Unterscheidung zwischen view und copy hat.

Dies ist keine gute Verwendung von numpy Arrays, nicht einmal die Objekt dtype Version. Es ist ein lehrreiches Beispiel, aber zu verwirrend, um praktisch zu sein. Wenn Sie eine deepcopy für ein Array tun müssen, verwenden Sie wahrscheinlich Arrays falsch.