Python-Bibliothek pandas 2.0 optimiert die Speicherverwaltung

Seite 2: Separierte Daten mit Copy-on-Write

Inhaltsverzeichnis

pandas 1.5.0 hat erstmals den Mechanismus Copy-on-Write (CoW) eingeführt. Mit pandas 2.0 ist die Implementierung weit genug fortgeschritten, um CoW ohne Schwierigkeiten zu verwenden. CoW ist aber noch nicht standardmäßig aktiviert.

Copy-on-Write bedeutet, dass sich jedes aus einem pandas-Objekt erzeugte neue pandas-Objekt so verhält, als wären die darunter liegenden Daten kopiert worden. Es ist insbesondere nicht mehr erlaubt, zwei verschiedene Objekte durch eine Operation zu verändern.

Wenn CoW nicht aktiviert ist, kann die folgende Operation zwei Objekte verändern:

df = pd.DataFrame({"a": [1, 2, 3], "b": 1})
view = df["a"]
view.iloc[0] = 100


# df:

     a  b
0  100  1
1    2  1
2    3  1

Der Code verändert sowohl df als auch view, da das Objekt view eine View auf die Daten von df ist. Das ist zum einen nicht leicht zu verstehen, da man wissen muss, ob ein Objekt eine View oder eine Kopie der ursprünglichen Daten ist. Außerdem verursachte das Vorgehen viele SettingWithCopyWarnings. Copy-on-Write vereinfacht die APIs der Methoden und verbessert gleichzeitig die durchschnittliche Performance.

pd.options.mode.copy_on_write = True

df = pd.DataFrame({"a": [1, 2, 3], "b": 1})
view = df["a"]
view.iloc[0] = 100


# df:

python
   a  b
0  1  1
1  2  1
2  3  1

CoW stellt sicher, dass pandas die Daten von view kopiert, bevor die iloc-Operation die Daten aktualisiert. Mit aktiviertem CoW ändert der Code demnach nur view, während df konstant bleibt. Dadurch sind Operationen berechenbarer und die API ist einfacher zu verstehen.

Die Umsetzung erfordert in diesem Fall eine zuvor nicht benötigte Kopie, was zunächst einen Performanceverlust bedeutet. Da es mit CoW nicht möglich ist, zwei Objekte mit einer Operation zu verändern, kann pandas jedoch in vielen anderen Bereichen auf defensive Kopien verzichten. Nahezu alle Methoden innerhalb von pandas haben die Daten eines DataFrame kopiert. Diese Kopien entfallen in pandas 2.0, wenn CoW aktiviert ist. Das Team hat bislang mehr als 60 Methoden optimiert. Die Library erstellt die Kopie erst beim Modifizieren eines DataFrame. Deswegen sollte CoW dazu beitragen, dass sich der durchschnittliche pandas-Workflow beschleunigt.

Entwicklerinnen und Entwickler können indirekt beeinflussen, wann pandas eine Kopie erstellt. Wenn die Inputvariable durch den Output einer Methode überschrieben wird, teilt sich das neue Objekt keine Daten mehr mit dem alten:

df = pd.DataFrame({"a": [1, 2, 3], "b": 1})
df = df.reset_index()
df.iloc[0, 0]

In diesem Fall muss die Library keine Kopie erstellen, da das alte Objekt nicht mehr existiert und Änderungen somit nur ein Objekt betreffen.

Ein Nebeneffekt von CoW ist, dass das ChainedAssignment, das für die meisten SettingWithCopyWarnings verantwortlich ist, konsistent nicht mehr funktioniert:

df = pd.DataFrame({"a": [1, 2, 3], "b": 1})
df["a"][df["b"] > 4] = 100

Solche Anweisungen haben bisher je nach Anordnung der Operationen funktioniert. Beim Austausch der Filter wird df auch jetzt nicht aktualisiert. Diese Anweisung erzeugt mit CoW eine ChainedAssignmentError-Warnung und lässt df unverändert.

Diese Anweisung lässt sich zu einer loc-Operation umformen, die auch mit CoW funktioniert:

df = pd.DataFrame({"a": [1, 2, 3], "b": 1})
df.loc[df["b"] > 4, "a"] = 100

Im Zuge der Weiterentwicklung von CoW kam zudem der Vorschlag auf, die Parameter copy und inplace weitgehend aus pandas zu entfernen. Die Diskussion findet im zugehörigen Pull Request auf GitHub statt.

Grundsätzlich rät der Autor dazu, neue Anwendungen unter Copy-on-Write zu entwickeln. Derzeit ist geplant, dass CoW mit dem nächsten Major Release für alle Anwendungen aktiviert ist, und es soll voraussichtlich keinen Nicht-CoW-Modus mehr geben. Wenn bisherige Anwendungen nicht darauf angewiesen sind, dass eine Operation mehrere Objekte modifiziert, verhindert der CoW-Modus einige Fehler. Grundsätzlich sollte er außerdem die Performance verbessern.

Die letzte Version der 1.x-Serie (1.5.3) zeigte gut 150 Warnungen für Anpassungen in pandas 2.0, die nicht kompatibel mit alten Versionen sind. Folgende Änderungen können potenziell größere Auswirkungen haben:

  • Der standardmäßig vergebene Datentyp für eine leere Series ist nun object statt float64.
  • Ein Index kann ab pandas 2.0 mit beliebigen NumPy-Datentypen umgehen und ist immer als Index repräsentiert. Frühere Versionen haben dafür unter anderem Klassen wie Int64Index verwendet, die nun entfernt wurden.
  • Der Parameter numeric_only ist nun konsistent über alle Aggregationsfunktionen hinweg implementiert. Außerdem ist der Default-Wert False. Aggregationen mit nicht numerische Spalten lösen neuerdings einen Fehler aus. Früheren Versionen haben für einige Funktionen die Spalte entfernt und für andere ebenfalls einen Fehler ausgegeben. Die Anpassung soll verhindern, dass unbeabsichtigt nicht numerische Spalten aus dem DataFrame verschwinden.

Anwendungen, die unter 1.5.3 keine Warnungen ausgeben, sollten problemlos mit pandas 2.0 zusammenarbeiten.