Direkt zum Inhalt

SettingWithCopyWarning in Pandas: Wie man diese Warnung behebt

Lerne, wie du Pandas' SettingWithCopyWarning beheben kannst: Es wird versucht, einen Wert auf eine Kopie eines Slice aus einem DataFrame zu setzen.
Aktualisierte 17. Nov. 2024  · 8 Min. Lesezeit

SettingWithCopyWarning ist eine Warnung, die Pandas ausgeben kann, wenn wir eine Zuweisung an einen DataFrame vornehmen. Das kann passieren, wenn wir verkettete Zuweisungen verwenden oder wenn wir einen DataFrame verwenden, der aus einem Slice erstellt wurde. Das ist eine häufige Fehlerquelle in Pandas-Code, mit der wir alle schon einmal zu tun hatten. Die Fehlersuche kann schwierig sein, weil die Warnung in einem Code auftauchen kann, der so aussieht, als ob er gut funktionieren würde.

Es ist wichtig, die SettingWithCopyWarning zu verstehen, denn sie weist auf mögliche Probleme bei der Datenmanipulation hin. Diese Warnung deutet darauf hin, dass dein Code die Daten möglicherweise nicht wie beabsichtigt verändert, was zu unbeabsichtigten Folgen und obskuren Fehlern führen kann, die schwer zu finden sind.

In diesem Artikel werden wir die SettingWithCopyWarning in Pandas untersuchen und wie man sie vermeiden kann. Wir werden auch über die Zukunft von Pandas sprechen und darüber, wie die Option copy_on_write unsere Arbeit mit DataFrames verändern wird.

DataFrame Ansichten und Kopien

Wenn wir einen Ausschnitt eines DataFrames auswählen und ihn einer Variablen zuweisen, können wir entweder eine Ansicht oder eine neue Kopie des DataFrames erhalten.

Bei einer Ansicht wird der Speicher von beiden DataFrames gemeinsam genutzt. Das bedeutet, dass die Änderung eines Wertes in einer Zelle, die in beiden DataFrames vorkommt, auch beide DataFrames verändert.

Beispiel für eine Pandas DataFrame-Ansicht

Bei einer Kopie wird neuer Speicher zugewiesen und ein unabhängiger DataFrame mit denselben Werten wie der ursprüngliche erstellt. In diesem Fall handelt es sich bei beiden DataFrames um unterschiedliche Entitäten, sodass die Änderung eines Wertes in einem der beiden DataFrames keine Auswirkungen auf den anderen hat.

Beispiel für eine DataFrame-Kopie

Pandas versucht, die Erstellung einer Kopie zu vermeiden, wenn es möglich ist, um die Leistung zu optimieren. Es ist jedoch unmöglich, im Voraus zu sagen, ob wir eine Ansicht oder eine Kopie erhalten werden. Die SettingWithCopyWarning wird immer dann ausgelöst, wenn wir einem DataFrame einen Wert zuweisen, bei dem unklar ist, ob es sich um eine Kopie oder eine Ansicht eines anderen DataFrame handelt.

Das Verstehen der SettingWithCopyWarning mit echten Daten

Wir werden diesen Kaggle-Datensatz "Real Estate Data London 2024 " verwenden, um zu lernen, wie die SettingWithCopyWarning entsteht und wie man sie beheben kann. 

Dieser Datensatz enthält aktuelle Immobiliendaten aus London. Hier ist ein Überblick über die Spalten im Datensatz:

  • addedOn: Das Datum, an dem der Eintrag hinzugefügt wurde.
  • title: Der Titel des Angebots.
  • descriptionHtml: Eine HTML-Beschreibung des Eintrags.
  • propertyType: Die Art der Immobilie. Der Wert wird "Not Specified" sein, wenn der Typ nicht angegeben wurde.
  • sizeSqFeetMax: Die maximale Größe in Quadratmetern.
  • bedrooms: Die Anzahl der Schlafzimmer.
  • listingUpdatedReason: Grund für die Aktualisierung des Angebots (z. B. neues Angebot, Preissenkung).
  • price: Der Preis des Angebots in Pfund.

Beispiel mit einer expliziten temporären Variablen

Nehmen wir an, dass es sich bei den Grundstücken mit einem nicht spezifizierten Eigenschaftstyp um Häuser handelt. Wir wollen also alle Zeilen mit propertyType gleich "Not Specified" auf "House" aktualisieren. Eine Möglichkeit, dies zu tun, besteht darin, die Zeilen mit einem nicht spezifizierten Eigenschaftstyp in eine temporäre DataFrame-Variable zu filtern und die propertyType Spaltenwerte wie folgt zu aktualisieren:

import pandas as pd
dataset_name = "realestate_data_london_2024_nov.csv"
df = pd.read_csv(dataset_name)

# Obtain all rows with unspecified property type
no_property_type = df[df["propertyType"] == "Not Specified"]

# Update the property type to “House” on those rows
no_property_type["propertyType"] = "House"

Wenn du diesen Code ausführst, erzeugt Pandas die SettingWithCopyWarning:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  no_property_type["propertyType"] = "House"

Der Grund dafür ist, dass Pandas nicht wissen kann, ob der no_property_type DataFrame eine Ansicht oder eine Kopie von df ist. 

Wenn wir einen Teil des DataFrames einer Variablen zuweisen, können wir entweder eine Ansicht oder eine Kopie erhalten, aber wir können nicht wissen, welche wir bekommen haben.

Das ist ein Problem, weil das Verhalten des folgenden Codes sehr unterschiedlich sein kann, je nachdem, ob es sich um eine Ansicht oder eine Kopie handelt. 

In diesem Beispiel geht es darum, den ursprünglichen DataFrame zu verändern. Dies geschieht nur, wenn no_property_type eine Ansicht ist. Wenn der Rest unseres Codes davon ausgeht, dass df geändert wurde, kann er falsch sein, weil es keine Möglichkeit gibt, dies zu garantieren. Wegen dieses unsicheren Verhaltens wirft Pandas die Warnung aus, um uns über diese Tatsache zu informieren.

Selbst wenn unser Code korrekt ausgeführt wird, weil wir eine Ansicht erhalten haben, könnten wir bei späteren Durchläufen eine Kopie erhalten, und der Code funktioniert nicht wie vorgesehen. Deshalb ist es wichtig, diese Warnung nicht zu ignorieren und sicherzustellen, dass unser Code immer das tut, was wir wollen.

Beispiel mit einer versteckten temporären Variable

Im vorherigen Beispiel ist klar, dass eine temporäre Variable verwendet wird, weil wir einen Teil des DataFrames explizit einer Variablen namens no_property_type zuweisen.

In manchen Fällen ist dies jedoch nicht so eindeutig. Das häufigste Beispiel, in dem SettingWithCopyWarning auftritt, ist die verkettete Indizierung. Nehmen wir an, dass wir die letzten beiden Zeilen durch eine einzige Zeile ersetzen:

df[df["propertyType"] == "Not Specified"]["propertyType"] = "House"

Auf den ersten Blick sieht es nicht so aus, als würde eine temporäre Variable erstellt werden. Die Ausführung führt aber auch zu einer SettingWithCopyWarning

Die Art und Weise, wie dieser Code ausgeführt wird, ist:

  1. df[df["propertyType"] == "Not Specified"] wird ausgewertet und vorübergehend im Speicher abgelegt. 
  2. Es wird auf den Index ["propertyType"] dieses temporären Speicherplatzes zugegriffen. 

Indexzugriffe werden einzeln ausgewertet und daher führt eine verkettete Indexierung zu derselben Warnung, da wir nicht wissen, ob die Zwischenergebnisse Ansichten oder Kopien sind

Indexzugriffe werden einzeln ausgewertet, und deshalb führt eine verkettete Indexierung zu derselben Warnung, weil wir nicht wissen, ob die Zwischenergebnisse Ansichten oder Kopien sind. Der obige Code ist im Wesentlichen das Gleiche, wie zu tun:

tmp = df[df["propertyType"] == "Not Specified"]
tmp["propertyType"] = "House"

Dieses Beispiel wird oft als verkettete Indizierung bezeichnet, weil wir die indizierten Zugriffe mit [] verketten. Zuerst rufen wir [df["propertyType"] == "Not Specified"] und dann ["propertyType"] auf.

Verkettete Indizierung

Wie löst man die SettingWithCopyWarning

Wir lernen, wie wir unseren Code so schreiben, dass es keine Unklarheiten gibt und die SettingWithCopyWarning nicht ausgelöst wird. Wir haben herausgefunden, dass die Warnung auf eine Unklarheit darüber zurückzuführen ist, ob ein DataFrame eine Ansicht oder eine Kopie eines anderen DataFrame ist.

Um dies zu beheben, müssen wir sicherstellen, dass jeder DataFrame, den wir erstellen, eine Kopie ist, wenn er eine Kopie sein soll, oder eine Ansicht, wenn er eine Ansicht sein soll.

Sicheres Ändern des ursprünglichen DataFrame mit loc 

Korrigieren wir den Code aus dem obigen Beispiel, in dem wir den ursprünglichen DataFrame verändern wollen. Um die Verwendung einer temporären Variablen zu vermeiden, verwende die Eigenschaft loc indexer.

df.loc[df["propertyType"] == "Not Specified", "propertyType"] = "House"

Mit diesem Code wirken wir über die loc indexer-Eigenschaft direkt auf den ursprünglichen df DataFrame ein, sodass keine Zwischenvariablen benötigt werden. Genau das müssen wir tun, wenn wir den ursprünglichen DataFrame direkt ändern wollen.

Das mag auf den ersten Blick wie eine verkettete Indizierung aussehen, weil es noch Parameter gibt, aber das ist es nicht. Jede Indizierung wird durch die eckigen Klammern [] definiert.

Loc-Doppelindex vs. verkettete Indizierung

Beachte, dass die Verwendung von loc nur sicher ist, wenn wir einen Wert direkt zuweisen, wie wir es oben getan haben. Wenn wir stattdessen eine temporäre Variable verwenden, stoßen wir wieder auf das gleiche Problem. Hier sind zwei Beispiele für Code, die das Problem nicht beheben: 

  1. Verwendung von loc mit einer temporären Variablen:
# Using loc plus temporary variable doesn’t fix the issue
no_property_type = df.loc[df["propertyType"] == "Not Specified"]
no_property_type["propertyType"] = "House"
  1. Verwendung von loc zusammen mit einem Index (wie bei der verketteten Indizierung):
# Using loc plus indexing is the same as chained indexing
df.loc[df["propertyType"] == "Not Specified"]["propertyType"] = "House"

Diese beiden Beispiele verwirren die Menschen, denn es ist ein weit verbreiteter Irrglaube, dass wir die ursprünglichen Daten verändern, solange es eine loc gibt. Das ist falsch. Die einzige Möglichkeit, um sicherzustellen, dass der Wert dem ursprünglichen DataFrame zugewiesen wird, ist die direkte Zuweisung mit einem einzigen loc ohne separate Indizierung.

Sicheres Arbeiten mit einer Kopie des ursprünglichen DataFrame mit copy()

Wenn wir sicherstellen wollen, dass wir mit einer Kopie des DataFrame arbeiten, sollten wir die die Methode .copy() .

Nehmen wir an, wir sollen den Preis pro Quadratmeter der Immobilien analysieren. Wir wollen die Originaldaten nicht verändern. Das Ziel ist es, einen neuen DataFrame mit den Analyseergebnissen zu erstellen und an ein anderes Team zu senden.

Der erste Schritt besteht darin, einige Zeilen herauszufiltern und die Daten zu bereinigen. Konkret müssen wir:

  • Entferne die Zeilen, in denen sizeSqFeetMax nicht definiert ist.
  • Entferne die Zeilen, in denen die price "POA" ist (Preis auf Anfrage).
  • Konvertiere die Preise in numerische Werte (im Originaldatensatz sind die Preise Strings mit folgendem Format: "£25,000,000")

Wir können die oben genannten Schritte mit folgendem Code ausführen:

# 1. Filter out all properties without a size or a price
properties_with_size_and_price = df[df["sizeSqFeetMax"].notna() & (df["price"] != "POA")]

# 2. Remove the £ and , characters from the price columns
properties_with_size_and_price["price"] = properties_with_size_and_price["price"].str.replace("£", "", regex=False).str.replace(",", "", regex=False)

# 3. Convert the price column to numeric values
properties_with_size_and_price["price"] = pd.to_numeric(properties_with_size_and_price["price"])

Um den Preis pro Quadratfuß zu berechnen, erstellen wir eine neue Spalte, deren Werte das Ergebnis der Division der Spalte price durch die Spalte sizeSqFeetMax sind:

properties_with_size_and_price["pricePerSqFt"] = properties_with_size_and_price["price"] / properties_with_size_and_price["sizeSqFeetMax"]

Wenn wir diesen Code ausführen, erhalten wir wieder die SettingWithCopyWarning. Das sollte keine Überraschung sein, denn wir haben explizit eine temporäre DataFrame-Variable properties_with_size_and_price erstellt und geändert.

Da wir mit einer Kopie der Daten und nicht mit dem Original-DataFrame arbeiten wollen, können wir das Problem beheben, indem wir sicherstellen, dass properties_with_size_and_price eine neue DataFrame-Kopie und keine Ansicht ist, indem wir die Methode .copy() in der ersten Zeile verwenden:

properties_with_size_and_price = df[df["sizeSqFeetMax"].notna() & (df["price"] != "POA")].copy()

Sicheres Hinzufügen neuer Spalten

Das Erstellen neuer Spalten verhält sich genauso wie das Zuweisen von Werten. Wenn es nicht eindeutig ist, ob wir mit einer Kopie oder einer Ansicht arbeiten, gibt Pandas eine SettingWithCopyWarning aus.

Wenn wir mit einer Kopie der Daten arbeiten wollen, sollten wir sie explizit mit der Methode .copy() kopieren. Dann können wir eine neue Spalte zuweisen, wie wir wollen. Das haben wir getan, als wir im vorherigen Beispiel die Spalte pricePerSqFt erstellt haben.

Wenn wir hingegen den ursprünglichen DataFrame verändern wollen, gibt es zwei Fälle, die wir berücksichtigen müssen. 

  1. Wenn sich die neue Spalte über alle Zeilen erstreckt, können wir den ursprünglichen DataFrame direkt ändern. Das führt zu keiner Warnung, weil wir keine Teilmenge der Zeilen auswählen werden. Wir könnten zum Beispiel für jede Zeile, in der der Haustyp fehlt, eine Spalte note hinzufügen: 
df["notes"] = df["propertyType"].apply(lambda house_type: "Missing house type" if house_type == "Not Specified" else "")
  1. Wenn die neue Spalte nur Werte für eine Teilmenge der Zeilen definiert, können wir die Eigenschaft loc indexer verwenden. Zum Beispiel:
df.loc[df["propertyType"] == "Not Specified", "notes"] = "Missing house type"

Beachte, dass in diesem Fall der Wert in den Spalten, die nicht ausgewählt wurden, undefiniert ist. Daher ist der erste Ansatz vorzuziehen, da wir so für jede Zeile einen Wert angeben können.

SettingWithCopyWarning Fehler in Pandas 3.0

Im Moment ist SettingWithCopyWarning nur eine Warnung, kein Fehler. Unser Code wird trotzdem ausgeführt und Pandas informiert uns lediglich, dass wir vorsichtig sein sollen. 

Laut der der offiziellen Pandas-Dokumentationwird SettingWithCopyWarning ab Version 3.0 nicht mehr verwendet und durch einen tatsächlichen Fehler ersetzt, um strengere Codestandards zu erzwingen.

Informationen zum Pandas 3.0 Update

Um sicherzustellen, dass unser Code mit zukünftigen Versionen von Pandas kompatibel bleibt, wird empfohlen, ihn bereits jetzt so zu aktualisieren, dass er einen Fehler statt einer Warnung auslöst.

Dies geschieht, indem du nach dem Import von Pandas die folgende Option setzt:

import pandas as pd
pd.options.mode.copy_on_write = True

Indem wir dies zum bestehenden Code hinzufügen, stellen wir sicher, dass wir jede mehrdeutige Zuweisung in unserem Code behandeln und dass der Code auch noch funktioniert, wenn wir auf Pandas 3.0 aktualisieren.

Fazit

Die SettingWithCopyWarning tritt immer dann auf, wenn unser Code nicht klar erkennen lässt, ob ein Wert, den wir ändern, eine Ansicht oder eine Kopie ist. Wir können das Problem lösen, indem wir immer klar sagen, was wir wollen:

  • Wenn wir mit einer Kopie arbeiten wollen, sollten wir sie explizit mit der Methode copy() kopieren.
  • Wenn wir den ursprünglichen DataFrame verändern wollen, sollten wir die loc indexer-Eigenschaft verwenden und den Wert direkt beim Zugriff auf die Daten zuweisen, ohne Zwischenvariablen zu verwenden.

Obwohl es sich nicht um einen Fehler handelt, sollten wir diese Warnung nicht ignorieren, da sie zu unerwarteten Ergebnissen führen kann. Außerdem wird es ab Pandas 3.0 standardmäßig ein Fehler sein, also sollten wir unseren Code zukunftssicher machen, indem wir Copy-on-Write in unserem aktuellen Code mit der pd.options.mode.copy_on_write = True aktivieren. So wird sichergestellt, dass der Code auch in zukünftigen Versionen von Pandas funktioniert.

FAQs

Warum bekomme ich SettingWithCopyWarning, auch wenn ich .loc verwende?

Die Verwendung von loc ist immer sicher und führt weder zu einer Warnung noch zu unerwartetem Verhalten, vorausgesetzt, dass df nicht aus einem anderen DataFrame erstellt wurde. Wenn df zum Beispiel der DataFrame ist, der beim Lesen des Datensatzes erstellt wurde, dann ist es sicher. Wenn es sich jedoch um das Ergebnis einer Zwischenberechnung handelt, dann ist es nur sicher, wenn der DataFrame mit der Methode copy() kopiert wurde.

Wie kann ich SettingWithCopyWarning unterdrücken?

Wir können das warnings Paket verwenden und den Code hinzufügen:

import warnings
warnings.simplefilter(action='ignore', category=pd.errors.SettingWithCopyWarning)

Es wird jedoch dringend davon abgeraten, diese Warnung zu unterdrücken oder zu ignorieren, da sie bedeutet, dass dein Code möglicherweise nicht das tut, was du glaubst, dass er tut.

Wie kann ich SettingWithCopyWarning ignorieren?

Wir können die Warnung vorübergehend ignorieren, indem wir das Paket warnings verwenden und unseren Code mit "Wrapping" versehen:

import warnings
with warnings.catch_warnings():
    warnings.simplefilter("ignore", category=pd.errors.SettingWithCopyWarning)
  # Our code goes here

Es wird jedoch dringend davon abgeraten, diese Warnung zu unterdrücken oder zu ignorieren, da sie bedeutet, dass dein Code möglicherweise nicht das tut, was du glaubst, dass er tut.

Wie kann ich SettingWithCopyWarning beheben, wenn ich eine neue Spalte hinzufüge?

Das Beheben der Warnung beim Hinzufügen einer Spalte erfolgt auf die gleiche Weise wie beim Zuweisen von Werten. Achte darauf, den DataFrame zuerst zu kopieren, wenn du mit einer Kopie der Daten arbeiten oder loc verwenden willst.

Ich habe diesen Leitfaden befolgt und erhalte immer noch die SettingWithCopyWarning. Wie kann ich es reparieren?

Bei den neuesten Versionen von Pandas sollte es keine Warnung geben, wenn du den Anweisungen in diesem Tutorial folgst.

Wenn du eine ältere Version verwendest, raten wir dir, sie auf die neueste stabile Version zu aktualisieren. Ältere Versionen sind dafür bekannt, dass sie Bugs haben und diese Warnung auslösen, obwohl es kein Problem mit dem Code gibt.

Wenn die Pandas-Version auf dem neuesten Stand ist, ist es wahrscheinlich, dass das zugrunde liegende Problem ein Fall von nicht offensichtlicher verketteter Indizierung ist. Überprüfe sorgfältig, wie der DataFrame erstellt wurde.


Photo of François Aubry
Author
François Aubry
LinkedIn
Das Unterrichten war schon immer meine Leidenschaft. Schon als Schülerin habe ich eifrig nach Möglichkeiten gesucht, anderen Schülern Nachhilfe zu geben und sie zu unterstützen. Diese Leidenschaft führte dazu, dass ich einen Doktortitel anstrebte, wobei ich auch als Lehrassistentin tätig war, um meine akademischen Bemühungen zu unterstützen. In diesen Jahren fand ich im traditionellen Klassenzimmer große Erfüllung, indem ich Verbindungen förderte und das Lernen erleichterte. Mit dem Aufkommen von Online-Lernplattformen erkannte ich jedoch das transformative Potenzial der digitalen Bildung. Ich war sogar aktiv an der Entwicklung einer solchen Plattform an unserer Hochschule beteiligt. Es ist mir ein großes Anliegen, traditionelle Unterrichtsprinzipien mit innovativen digitalen Methoden zu verbinden. Meine Leidenschaft ist es, Kurse zu erstellen, die nicht nur ansprechend und informativ, sondern auch für Lernende im digitalen Zeitalter zugänglich sind.
Themen

Lerne Pandas mit diesen Kursen!

Kurs

Joining Data with pandas

4 hr
164.3K
Learn to combine data from multiple tables by joining data together using pandas.
Siehe DetailsRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Die 20 besten Snowflake-Interview-Fragen für alle Niveaus

Bist du gerade auf der Suche nach einem Job, der Snowflake nutzt? Bereite dich mit diesen 20 besten Snowflake-Interview-Fragen vor, damit du den Job bekommst!
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

20 Min.

Der Blog

Die 32 besten AWS-Interview-Fragen und Antworten für 2024

Ein kompletter Leitfaden zur Erkundung der grundlegenden, mittleren und fortgeschrittenen AWS-Interview-Fragen, zusammen mit Fragen, die auf realen Situationen basieren. Es deckt alle Bereiche ab und sorgt so für eine abgerundete Vorbereitungsstrategie.
Zoumana Keita 's photo

Zoumana Keita

30 Min.

Der Blog

Top 30 Generative KI Interview Fragen und Antworten für 2024

Dieser Blog bietet eine umfassende Sammlung von Fragen und Antworten zu generativen KI-Interviews, die von grundlegenden Konzepten bis hin zu fortgeschrittenen Themen reichen.
Hesam Sheikh Hassani's photo

Hesam Sheikh Hassani

15 Min.

See MoreSee More