Cursus
SettingWithCopyWarning is een waarschuwing die Pandas kan geven wanneer we een toewijzing doen aan een DataFrame. Dit kan gebeuren wanneer we chained assignments gebruiken of wanneer we een DataFrame gebruiken dat is gemaakt vanuit een slice. Het is een veelvoorkomende bron van bugs in Pandas-code waar we allemaal wel eens mee te maken hebben gehad. Het kan lastig zijn te debuggen omdat de waarschuwing kan verschijnen in code die er op het eerste gezicht prima uitziet.
De SettingWithCopyWarning begrijpen is belangrijk omdat het mogelijke problemen met datamanipulatie aangeeft. Deze waarschuwing suggereert dat je code de data misschien niet wijzigt zoals bedoeld, wat kan leiden tot ongewenste gevolgen en lastige, moeilijk te traceren bugs.
In dit artikel bekijken we de SettingWithCopyWarning in pandas en hoe je die kunt vermijden. We bespreken ook de toekomst van Pandas en hoe de optie copy_on_write zal veranderen hoe we met DataFrames werken.
DataFrame-views en -kopieën
Als we een slice van een DataFrame selecteren en aan een variabele toewijzen, krijgen we ofwel een view of een nieuwe DataFrame-kopie.
Bij een view wordt het geheugen tussen beide DataFrames gedeeld. Dit betekent dat het wijzigen van een waarde in een cel die in beide DataFrames voorkomt, ze allebei zal wijzigen.

Bij een kopie wordt nieuw geheugen toegewezen en wordt een onafhankelijk DataFrame gemaakt met dezelfde waarden als het origineel. In dit geval zijn beide DataFrames aparte entiteiten, dus het wijzigen van een waarde in de ene heeft geen invloed op de andere.

Pandas probeert waar mogelijk het maken van een kopie te vermijden om de performance te optimaliseren. Het is echter onmogelijk om van tevoren te voorspellen of we een view of een kopie krijgen. De SettingWithCopyWarning wordt gegeven wanneer we een waarde toewijzen aan een DataFrame waarvan onduidelijk is of het een kopie is of een view van een ander DataFrame.
De SettingWithCopyWarning begrijpen met echte data
We gebruiken deze Real Estate Data London 2024-dataset van Kaggle om te leren hoe de SettingWithCopyWarning optreedt en hoe je die oplost.
Deze dataset bevat recente vastgoeddata uit Londen. Hier is een overzicht van de kolommen in de dataset:
addedOn: De datum waarop de aanbieding is toegevoegd.title: De titel van de aanbieding.descriptionHtml: Een HTML-beschrijving van de aanbieding.propertyType: Het type woning. De waarde is"Not Specified"als het type niet is opgegeven.sizeSqFeetMax: De maximale grootte in square feet.bedrooms: Het aantal slaapkamers.listingUpdatedReason: Reden voor het bijwerken van de aanbieding (bijv. nieuwe listing, prijsverlaging).price: De prijs van de aanbieding in ponden.
Voorbeeld met een expliciete tijdelijke variabele
Stel dat ons wordt verteld dat woningen met een niet-gespecificeerd type huizen zijn. We willen dus alle rijen met propertyType gelijk aan "Not Specified" bijwerken naar "House". Eén manier om dit te doen is de rijen met een niet-gespecificeerd type te filteren in een tijdelijke DataFrame-variabele en de waarden in de kolom propertyType zo bij te werken:
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"
Het uitvoeren van deze code zorgt ervoor dat pandas de SettingWithCopyWarning geeft:
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"
De reden hiervoor is dat pandas niet kan weten of het DataFrame no_property_type een view is of een kopie van df.

Dit is een probleem omdat het gedrag van de volgende code sterk kan verschillen, afhankelijk van of het een view of een kopie is.
In dit voorbeeld is ons doel het oorspronkelijke DataFrame te wijzigen. Dat gebeurt alleen als no_property_type een view is. Als de rest van onze code ervan uitgaat dat df is gewijzigd, kan dat fout zijn, omdat er geen garantie is dat dat zo is. Vanwege dit onzekere gedrag geeft Pandas de waarschuwing om ons daarop te wijzen.
Zelfs als onze code correct draait omdat we een view kregen, kunnen we bij volgende runs een kopie krijgen en werkt de code niet meer zoals bedoeld. Daarom is het belangrijk deze waarschuwing niet te negeren en te zorgen dat onze code altijd doet wat we willen.
Voorbeeld met een verborgen tijdelijke variabele
In het vorige voorbeeld is het duidelijk dat een tijdelijke variabele wordt gebruikt, omdat we expliciet een deel van het DataFrame toewijzen aan een variabele met de naam no_property_type.
In sommige gevallen is dat echter minder expliciet. Het meest voorkomende voorbeeld waarbij SettingWithCopyWarning optreedt is chained indexing. Stel dat we de laatste twee regels vervangen door één regel:
df[df["propertyType"] == "Not Specified"]["propertyType"] = "House"
Op het eerste gezicht lijkt het niet alsof er een tijdelijke variabele wordt gemaakt. Toch resulteert het uitvoeren ervan ook in een SettingWithCopyWarning.
De manier waarop deze code wordt uitgevoerd is:
df[df["propertyType"] == "Not Specified"]wordt geëvalueerd en tijdelijk in het geheugen opgeslagen.- De index
["propertyType"]van die tijdelijke geheugenlocatie wordt benaderd.

Index-toegangen worden één voor één geëvalueerd en daarom geeft chained indexing dezelfde waarschuwing, omdat we niet weten of de tussentijdse resultaten views of kopieën zijn. De bovenstaande code is in wezen hetzelfde als:
tmp = df[df["propertyType"] == "Not Specified"]
tmp["propertyType"] = "House"
Dit voorbeeld wordt vaak chained indexing genoemd omdat we index-toegangen aaneenrijgen met []. Eerst benaderen we [df["propertyType"] == "Not Specified"] en daarna ["propertyType"].

Hoe los je de SettingWithCopyWarning op
Laten we leren hoe we onze code zo schrijven dat er geen dubbelzinnigheid is en de SettingWithCopyWarning niet wordt geactiveerd. We hebben geleerd dat de waarschuwing voortkomt uit onduidelijkheid over of een DataFrame een view of een kopie van een ander DataFrame is.
De manier om dit op te lossen is te zorgen dat elk DataFrame dat we maken een kopie is als we dat willen, of een view als we dat willen.
Het originele DataFrame veilig wijzigen met loc
Laten we de code uit het bovenstaande voorbeeld oplossen, waar we het originele DataFrame willen aanpassen. Gebruik om een tijdelijke variabele te vermijden de loc-indexeerproperty.
df.loc[df["propertyType"] == "Not Specified", "propertyType"] = "House"
Met deze code werken we direct op het oorspronkelijke df-DataFrame via de loc-indexeerproperty, dus er zijn geen tussenvariabelen nodig. Dit is wat we moeten doen wanneer we het originele DataFrame direct willen wijzigen.
Dit lijkt op het eerste gezicht op chained indexing omdat er nog steeds parameters zijn, maar dat is het niet. Wat elke indexing definieert, zijn de vierkante haken [].

Let op dat loc alleen veilig is als we direct een waarde toewijzen, zoals we hierboven deden. Als we in plaats daarvan een tijdelijke variabele gebruiken, vallen we weer in hetzelfde probleem. Hier zijn twee voorbeelden van code die het probleem niet oplossen:
locgebruiken met een tijdelijke variabele:
# Using loc plus temporary variable doesn’t fix the issue
no_property_type = df.loc[df["propertyType"] == "Not Specified"]
no_property_type["propertyType"] = "House"
locgebruiken samen met een index (hetzelfde als chained indexing):
# Using loc plus indexing is the same as chained indexing
df.loc[df["propertyType"] == "Not Specified"]["propertyType"] = "House"
Beide voorbeelden zorgen vaak voor verwarring omdat de misvatting leeft dat zolang er een loc is, we de originele data aanpassen. Dat klopt niet. De enige manier om te garanderen dat de waarde aan het originele DataFrame wordt toegewezen, is direct toewijzen met één enkele loc zonder aparte indexing.
Veilig werken met een kopie van het originele DataFrame met copy()
Als we zeker willen weten dat we op een kopie van het DataFrame werken, moeten we de methode .copy() gebruiken.
Stel dat we worden gevraagd de prijs per square foot van de woningen te analyseren. We willen de originele data niet wijzigen. Het doel is een nieuw DataFrame te maken met de analyseresultaten om naar een ander team te sturen.
De eerste stap is om enkele rijen te filteren en de data op te schonen. Concreet moeten we:
- De rijen verwijderen waar
sizeSqFeetMaxniet is gedefinieerd. - De rijen verwijderen waar de
price"POA"is (price on application). - De prijzen omzetten naar numerieke waarden (in de originele dataset zijn de prijzen strings met het volgende formaat:
"£25,000,000")
De bovenstaande stappen kunnen we uitvoeren met de volgende code:
# 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"])
Om de prijs per square foot te berekenen, maken we een nieuwe kolom waarvan de waarden het resultaat zijn van het delen van de kolom price door de kolom sizeSqFeetMax:
properties_with_size_and_price["pricePerSqFt"] = properties_with_size_and_price["price"] / properties_with_size_and_price["sizeSqFeetMax"]
Als we deze code uitvoeren, krijgen we opnieuw de SettingWithCopyWarning. Dat is geen verrassing, omdat we expliciet een tijdelijke DataFrame-variabele properties_with_size_and_price hebben gemaakt en gewijzigd.
Omdat we met een kopie van de data willen werken in plaats van het originele DataFrame, kunnen we het probleem oplossen door ervoor te zorgen dat properties_with_size_and_price een nieuwe DataFrame-kopie is en geen view, door op de eerste regel de methode .copy() te gebruiken:
properties_with_size_and_price = df[df["sizeSqFeetMax"].notna() & (df["price"] != "POA")].copy()
Veilig nieuwe kolommen toevoegen
Nieuwe kolommen aanmaken werkt hetzelfde als waarden toewijzen. Telkens wanneer het onduidelijk is of we met een kopie of een view werken, zal pandas een SettingWithCopyWarning geven.
Als we met een kopie van de data willen werken, moeten we die expliciet kopiëren met de methode .copy(). Daarna kunnen we op elke gewenste manier een nieuwe kolom toewijzen. Dat deden we toen we in het vorige voorbeeld de kolom pricePerSqFt maakten.
Aan de andere kant, als we het originele DataFrame willen wijzigen, zijn er twee gevallen om te overwegen.
- Als de nieuwe kolom elke rij omvat, kunnen we het originele DataFrame direct wijzigen. Dit geeft geen waarschuwing omdat we geen subset van de rijen selecteren. We zouden bijvoorbeeld een kolom
notekunnen toevoegen voor elke rij waar het woningtype ontbreekt:
df["notes"] = df["propertyType"].apply(lambda house_type: "Missing house type" if house_type == "Not Specified" else "")
- Als de nieuwe kolom alleen waarden definieert voor een subset van de rijen, dan kunnen we de
loc-indexeerproperty gebruiken. Bijvoorbeeld:
df.loc[df["propertyType"] == "Not Specified", "notes"] = "Missing house type"
Let op dat in dit geval de waarde in de niet-geselecteerde rijen ongedefinieerd zal zijn, dus de eerste aanpak heeft de voorkeur omdat we daarmee een waarde voor elke rij kunnen specificeren.
SettingWithCopyWarning-fout in Pandas 3.0
Op dit moment is SettingWithCopyWarning alleen een waarschuwing, geen fout. Onze code wordt nog steeds uitgevoerd en Pandas geeft ons simpelweg aan dat we voorzichtig moeten zijn.
Volgens de officiële Pandas-documentatie wordt SettingWithCopyWarning vanaf versie 3.0 niet meer gebruikt en standaard vervangen door een echte fout, wat strengere codestandaarden afdwingt.
Om ervoor te zorgen dat onze code compatibel blijft met toekomstige versies van pandas, is het aan te raden deze nu al bij te werken zodat er een fout wordt opgegooid in plaats van een waarschuwing.
Dit doe je door na het importeren van pandas de volgende optie te zetten:
import pandas as pd
pd.options.mode.copy_on_write = True
Door dit aan bestaande code toe te voegen, zorgen we dat we met elke dubbelzinnige toewijzing in onze code omgaan en dat de code blijft werken wanneer we updaten naar pandas 3.0.
Conclusie
De SettingWithCopyWarning treedt op wanneer onze code onduidelijk maakt of een waarde die we wijzigen een view of een kopie is. We kunnen dit oplossen door altijd expliciet te zijn over wat we willen:
- Als we met een kopie willen werken, moeten we die expliciet kopiëren met de methode
copy(). - Als we het originele DataFrame willen wijzigen, moeten we de
loc-indexeerproperty gebruiken en de waarde direct toewijzen bij het benaderen van de data, zonder tussenvariabelen.
Ondanks dat het geen fout is, moeten we deze waarschuwing niet negeren omdat dit tot onverwachte resultaten kan leiden. Bovendien wordt het vanaf Pandas 3.0 standaard een fout, dus we moeten onze code toekomstbestendig maken door Copy-on-Write in te schakelen in onze huidige code met pd.options.mode.copy_on_write = True. Zo blijft de code functioneren in toekomstige versies van Pandas.
Wil je meer leren over Pandas? Bekijk dan deze resources:
FAQs
Waarom krijg ik SettingWithCopyWarning zelfs als ik .loc gebruik?
Het gebruik van loc is altijd veilig en zal geen waarschuwing geven of tot onverwacht gedrag leiden, op voorwaarde dat df niet is gemaakt uit een ander DataFrame. Als df bijvoorbeeld het DataFrame is dat is gemaakt door de dataset in te lezen, dan is het veilig. Als het echter het resultaat is van een tussentijdse bewerking, dan is het alleen veilig als het DataFrame is gekopieerd met de methode copy().
Hoe onderdruk ik SettingWithCopyWarning?
We kunnen het pakket warnings gebruiken en de code toevoegen:
import warnings
warnings.simplefilter(action='ignore', category=pd.errors.SettingWithCopyWarning)
Het is echter sterk af te raden deze waarschuwing te onderdrukken of te negeren, omdat dit betekent dat je code mogelijk niet doet wat je denkt dat die doet.
Hoe negeer ik SettingWithCopyWarning?
We kunnen de waarschuwing tijdelijk negeren met het pakket warnings en onze code omsluiten met:
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=pd.errors.SettingWithCopyWarning)
# Our code goes here
Het is echter sterk af te raden deze waarschuwing te onderdrukken of te negeren, omdat dit betekent dat je code mogelijk niet doet wat je denkt dat die doet.
Hoe los ik SettingWithCopyWarning op bij het toevoegen van een nieuwe kolom?
De waarschuwing oplossen bij het toevoegen van een kolom gebeurt op dezelfde manier als bij het toewijzen van waarden. Zorg dat je het DataFrame eerst kopieert als je met een kopie wilt werken, of gebruik loc.
Ik heb deze gids gevolgd en krijg nog steeds de SettingWithCopyWarning. Hoe los ik het op?
In de meest recente versies van pandas zouden de praktijken uit deze tutorial geen enkele waarschuwing moeten geven.
Als je een oudere versie gebruikt, adviseren we te updaten naar de laatste stabiele versie. Oudere versies staan bekend om bugs rond deze waarschuwing en geven die soms ten onrechte.
Als de pandas-versie up-to-date is, is het waarschijnlijk dat het onderliggende probleem een geval van niet-zo-duidelijke chained indexing is. Controleer goed hoe het DataFrame is aangemaakt.


