Warum sollte ich eine Kopie eines Datenrahmens in Pandas erstellen?


182

Bei der Auswahl eines Unterdatenrahmens aus einem übergeordneten Datenrahmen habe ich festgestellt, dass einige Programmierer mit dieser .copy()Methode eine Kopie des Datenrahmens erstellen .

Warum machen sie eine Kopie des Datenrahmens? Was passiert, wenn ich keine Kopie mache?


6
Ich vermute, sie treffen zusätzliche Vorsichtsmaßnahmen, um den Quelldatenrahmen nicht zu ändern. Wahrscheinlich unnötig, aber wenn Sie etwas interaktiv zusammenwerfen, ist es sicherer als leid.
Paul H

8
Ich nehme an, dass dies keine dumme Frage ist, um eine negative Frage zu stellen.
Elizabeth Susan Joseph

Antworten:


200

Dies erweitert die Antwort von Paulus. In Pandas gibt die Indizierung eines DataFrame einen Verweis auf den ursprünglichen DataFrame zurück. Durch Ändern der Teilmenge wird daher der anfängliche DataFrame geändert. Daher möchten Sie die Kopie verwenden, wenn Sie sicherstellen möchten, dass sich der ursprüngliche DataFrame nicht ändert. Betrachten Sie den folgenden Code:

df = DataFrame({'x': [1,2]})
df_sub = df[0:1]
df_sub.x = -1
print(df)

Du wirst kriegen:

x
0 -1
1  2

Im Gegensatz dazu bleibt df unverändert:

df_sub_copy = df[0:1].copy()
df_sub_copy.x = -1

6
Ist das eine tiefe Kopie?
Bikashg

6
Ja. Der Standardmodus ist "tiefe" Kopie! pandas.pydata.org/pandas-docs/stable/reference/api/…
Ambareesh

44

Wenn Sie keine Kopie erstellen, können die Indizes auch dann an anderer Stelle bearbeitet werden, wenn Sie den dataFrame einem anderen Namen zuweisen.

Beispielsweise:

df2 = df
func1(df2)
func2(df)

func1 kann df durch Ändern von df2 ändern, um Folgendes zu vermeiden:

df2 = df.copy()
func1(df2)
func2(df)

Warte, warte, warte, kannst du erklären, WARUM dies geschieht? Macht keinen Sinn.
NoName

2
Dies liegt daran, dass im ersten Beispiel "df2 = df df , both variables reference the same DataFrame instance. So any changes made to " oder df2für dieselbe Objektinstanz erstellt wird. Während in der df2 = df.copy()zweiten Objektinstanz eine Kopie der ersten erstellt wird, werden jetzt dfund unter df2Bezugnahme auf verschiedene Objektinstanzen und etwaige Änderungen an der jeweiligen DataFrame-Instanz vorgenommen.
Pedro

17

Es muss erwähnt werden, dass die Rückgabe von Kopien oder Ansichten von der Art der Indizierung abhängt.

In der Pandas-Dokumentation heißt es:

Rückgabe einer Ansicht im Vergleich zu einer Kopie

Die Regeln für die Rückgabe einer Ansicht der Daten hängen vollständig von NumPy ab. Immer wenn ein Array von Beschriftungen oder ein boolescher Vektor an der Indizierungsoperation beteiligt sind, ist das Ergebnis eine Kopie. Bei der Indizierung und dem Schneiden einzelner Labels / Skalare, z. B. df.ix [3: 6] oder df.ix [:, 'A'], wird eine Ansicht zurückgegeben.



12

Der Hauptzweck besteht darin, eine verkettete Indizierung zu vermeiden und die zu beseitigen SettingWithCopyWarning.

Hier ist verkettete Indizierung so etwas wie dfc['A'][0] = 111

Das Dokument besagt, dass eine verkettete Indizierung in vermieden werden sollte Rückgabe einer Ansicht gegenüber einer Kopie . Hier ist ein leicht modifiziertes Beispiel aus diesem Dokument:

In [1]: import pandas as pd

In [2]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})

In [3]: dfc
Out[3]:
    A   B
0   aaa 1
1   bbb 2
2   ccc 3

In [4]: aColumn = dfc['A']

In [5]: aColumn[0] = 111
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [6]: dfc
Out[6]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

Hier aColumnist dies eine Ansicht und keine Kopie des ursprünglichen DataFrame. Wenn Sie also Änderungen vornehmen, aColumnwird das Original erstelltdfc geändert. Als nächstes, wenn wir zuerst die Zeile indizieren:

In [7]: zero_row = dfc.loc[0]

In [8]: zero_row['A'] = 222
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [9]: dfc
Out[9]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

Diesmal zero_row handelt es sich um eine Kopie, sodass das Original dfcnicht geändert wird.

Anhand dieser beiden obigen Beispiele sehen wir, dass es nicht eindeutig ist, ob Sie den ursprünglichen DataFrame ändern möchten oder nicht. Dies ist besonders gefährlich, wenn Sie Folgendes schreiben:

In [10]: dfc.loc[0]['A'] = 333
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [11]: dfc
Out[11]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

Diesmal hat es überhaupt nicht funktioniert. Hier wollten wir ändern dfc, aber wir haben tatsächlich einen Zwischenwert geändert dfc.loc[0], der eine Kopie ist und sofort verworfen wird. Es ist sehr schwer vorherzusagen, ob der Zwischenwert gefälltdfc.loc[0]dfc['A'] eine Ansicht oder eine Kopie ist oder ist, daher kann nicht garantiert werden, ob der ursprüngliche DataFrame aktualisiert wird oder nicht. Aus diesem Grund sollte eine verkettete Indizierung vermieden werden, und Pandas generiert das SettingWithCopyWarningUpdate für diese Art der verketteten Indizierung.

Jetzt ist die Verwendung von .copy() . Um die Warnung zu beseitigen, erstellen Sie eine Kopie, um Ihre Absicht ausdrücklich auszudrücken:

In [12]: zero_row_copy = dfc.loc[0].copy()

In [13]: zero_row_copy['A'] = 444 # This time no warning

Da Sie eine Kopie ändern, kennen Sie das Original dfc ändern niemals ändern wird, und Sie erwarten nicht, dass es sich ändert. Ihre Erwartung entspricht dem Verhalten, dann SettingWithCopyWarningverschwindet das.

Hinweis: Wenn Sie den ursprünglichen DataFrame ändern möchten, empfiehlt das Dokument die Verwendung von loc:

In [14]: dfc.loc[0,'A'] = 555

In [15]: dfc
Out[15]:
    A   B
0   555 1
1   bbb 2
2   ccc 3

2

Im Allgemeinen ist es sicherer, an Kopien zu arbeiten als an Originaldatenrahmen, es sei denn, Sie wissen, dass Sie das Original nicht mehr benötigen und mit der manipulierten Version fortfahren möchten. Normalerweise kann der ursprüngliche Datenrahmen immer noch mit der manipulierten Version usw. verglichen werden. Daher arbeiten die meisten Benutzer an Kopien und führen diese am Ende zusammen.


0

Angenommen, Sie haben einen Datenrahmen wie unten

df1
     A    B    C    D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0

Wenn Sie eine andere erstellen möchten, df2die mit df1, ohne identisch istcopy

df2=df1
df2
     A    B    C    D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0

Und möchte den df2-Wert nur wie folgt ändern

df2.iloc[0,0]='changed'

df2
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

Gleichzeitig wird auch der df1 geändert

df1
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

Da zwei df gleich sind object, können wir es mit dem überprüfenid

id(df1)
140367679979600
id(df2)
140367679979600

Sie übergeben also als dasselbe Objekt und ändern ein anderes den gleichen Wert.


Wenn wir das hinzufügen copy, und jetzt df1und df2werden als unterschiedlich angesehen object, wenn wir die gleiche Änderung an einer von ihnen tun das andere wird sich nicht ändern.

df2=df1.copy()
id(df1)
140367679979600
id(df2)
140367674641232

df1.iloc[0,0]='changedback'
df2
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

Gut zu erwähnen, wenn Sie den ursprünglichen Datenrahmen unterteilen, ist es sicher, auch die Kopie hinzuzufügen, um das zu vermeiden SettingWithCopyWarning

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.