Last chance! 50% off DataCamp Premium
Sale ends in
SettingWithCopyWarning, Pandas’ın bir DataFrame’e atama yaptığımızda yükseltebileceği bir uyarıdır. Bu, zincirleme atama yaptığımızda veya bir dilimden oluşturulmuş bir DataFrame kullandığımızda meydana gelebilir. Hepimizin daha önce karşılaştığı, Pandas kodlarında yaygın bir hata kaynağıdır. Uyarı, aslında düzgün çalışıyor gibi görünen kodlarda da belirebildiği için ayıklaması zor olabilir.
SettingWithCopyWarning’ı anlamak önemlidir çünkü veri manipülasyonunda olası sorunlara işaret eder. Bu uyarı, kodunuzun verileri amaçlandığı şekilde değiştirmiyor olabileceğini, bunun da istenmeyen sonuçlara ve izlenmesi zor, belirsiz hatalara yol açabileceğini gösterir.
Bu yazıda, pandas’taki SettingWithCopyWarning’ı ve bundan nasıl kaçınabileceğimizi inceleyeceğiz. Ayrıca Pandas’ın geleceğini ve copy_on_write seçeneğinin DataFrame’lerle çalışma şeklimizi nasıl değiştireceğini tartışacağız.
Bir DataFrame’den bir dilim seçip onu bir değişkene atadığımızda, bir görünüm (view) ya da yeni bir DataFrame kopyası elde edebiliriz.
Görünümde, her iki DataFrame de aynı belleği paylaşır. Bu, her iki DataFrame’de de bulunan bir hücredeki bir değeri değiştirmenin ikisini birden değiştireceği anlamına gelir.

Kopyada ise yeni bellek ayrılır ve orijinaliyle aynı değerlere sahip bağımsız bir DataFrame oluşturulur. Bu durumda, DataFrame’ler birbirinden ayrıdır; birinde yapılan değişiklik diğerini etkilemez.

Pandas, mümkün olduğunda performansı iyileştirmek için kopya oluşturmayı kaçınmaya çalışır. Ancak önceden bir görünüm mü yoksa kopya mı elde edeceğimizi öngörmek imkânsızdır. SettingWithCopyWarning, bir DataFrame’e değer atadığımızda ve bunun başka bir DataFrame’in görünümü mü yoksa kopyası mı olduğunun belirsiz olduğu durumlarda yükseltilir.
SettingWithCopyWarning’ı AnlamakSettingWithCopyWarning’ın nasıl oluştuğunu ve nasıl düzeltileceğini öğrenmek için Real Estate Data London 2024 adlı Kaggle veri setini kullanacağız.
Bu veri seti Londra’dan güncel emlak verileri içeriyor. Veri setinde bulunan sütunlara genel bir bakış:
addedOn: İlanın eklendiği tarih.title: İlanın başlığı.descriptionHtml: İlanın HTML açıklaması.propertyType: Mülkün türü. Tür belirtilmemişse değer "Not Specified" olur.sizeSqFeetMax: Maksimum büyüklük (fit kare cinsinden).bedrooms: Yatak odası sayısı.listingUpdatedReason: İlanın güncellenme nedeni (ör. yeni ilan, fiyat düşüşü).price: İlanın fiyatı (sterlin).Diyelim ki türü belirtilmeyen tüm mülklerin ev olduğunu söylediler. Bu nedenle, propertyType değeri "Not Specified" olan tüm satırları "House" olarak güncellemek istiyoruz. Bunu yapmanın bir yolu, türü belirtilmemiş satırları geçici bir DataFrame değişkenine filtrelemek ve propertyType sütununu şu şekilde güncellemektir:
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"
Bu kodu çalıştırmak, pandas’ın SettingWithCopyWarning üretmesine neden olur:
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"
Bunun nedeni, pandas’ın no_property_type DataFrame’inin df’in bir görünümü mü yoksa kopyası mı olduğunu bilememesidir.

Bu bir sorundur çünkü aşağıdaki kodun davranışı, bunun bir görünüm mü yoksa kopya mı olduğuna bağlı olarak çok farklı olabilir.
Bu örnekte amacımız, orijinal DataFrame’i değiştirmektir. Bu yalnızca no_property_type bir görünümse gerçekleşir. Geri kalan kodumuz df’in değiştiği varsayımıyla çalışıyorsa, bunun garanti edilmesinin bir yolu olmadığından yanlış olabilir. Bu belirsiz davranış nedeniyle Pandas, bizi bu durumdan haberdar etmek için uyarıyı verir.
Kodumuz görünüm elde ettiğimiz için doğru çalışsa bile, sonraki çalıştırmalarda kopya elde edebiliriz ve kod istenen şekilde çalışmaz. Bu nedenle, bu uyarıyı görmezden gelmemek ve kodumuzun her zaman istediğimiz işi yaptığından emin olmak önemlidir.
Önceki örnekte, DataFrame’in bir kısmını açıkça no_property_type adlı bir değişkene atadığımız için geçici bir değişken kullanıldığı açıktır.
Ancak bazı durumlarda bu kadar açık değildir. SettingWithCopyWarning’ın en sık görüldüğü örnek, zincirleme indekslemedir. Son iki satırı tek satırla değiştirdiğimizi varsayalım:
df[df["propertyType"] == "Not Specified"]["propertyType"] = "House"
İlk bakışta, geçici bir değişken oluşturuluyormuş gibi görünmez. Ancak bunu çalıştırmak da SettingWithCopyWarning ile sonuçlanır.
Bu kod şu şekilde yürütülür:
df[df["propertyType"] == "Not Specified"] değerlendirilir ve geçici olarak belleğe alınır. ["propertyType"] indeksi erişilir. 
İndeks erişimleri tek tek değerlendirilir; dolayısıyla, zincirleme indeksleme aynı uyarıyla sonuçlanır çünkü ara sonuçların görünüm mü yoksa kopya mı olduğunu bilmiyoruz. Yukarıdaki kod temelde şununla aynıdır:
tmp = df[df["propertyType"] == "Not Specified"]
tmp["propertyType"] = "House"
Bu örnek, [] kullanarak indeks erişimlerini zincirlediğimiz için sıklıkla zincirleme indeksleme olarak anılır. Önce [df["propertyType"] == "Not Specified"] sonra ["propertyType"]’e erişiriz.

SettingWithCopyWarning Nasıl ÇözülürKodumuzu belirsizlik olmayacak şekilde yazmayı ve SettingWithCopyWarning’ın tetiklenmemesini öğrenelim. Uyarının, bir DataFrame’in başka bir DataFrame’in görünümü mü yoksa kopyası mı olduğuna ilişkin belirsizlikten kaynaklandığını öğrendik.
Bunu düzeltmenin yolu, oluşturduğumuz her DataFrame’in, eğer kopya istiyorsak kopya, görünüm istiyorsak görünüm olduğundan emin olmaktır.
loc ile değiştirmek Orijinal DataFrame’i değiştirmek istediğimiz yukarıdaki örnekteki kodu düzeltelim. Geçici bir değişken kullanmaktan kaçınmak için loc indeksleyici özelliğini kullanın.
df.loc[df["propertyType"] == "Not Specified", "propertyType"] = "House"
Bu kodla, loc indeksleyicisi üzerinden doğrudan orijinal df DataFrame’i üzerinde işlem yapıyoruz; bu yüzden ara değişkenlere gerek yok. Orijinal DataFrame’i doğrudan değiştirmek istediğimizde yapmamız gereken budur.
İlk bakışta bu hâlâ parametreler içerdiğinden zincirleme indeksleme gibi görünebilir; ama değildir. Her bir indekslemeyi tanımlayan şey köşeli parantezlerdir [].

Şunu unutmayın: loc kullanmak yalnızca değeri doğrudan atadığımızda güvenlidir; yukarıda yaptığımız gibi. Eğer bunun yerine geçici bir değişken kullanırsak, yine aynı soruna düşeriz. İşte sorunu çözmeyen iki örnek kod:
loc kullanmak:# Using loc plus temporary variable doesn’t fix the issue
no_property_type = df.loc[df["propertyType"] == "Not Specified"]
no_property_type["propertyType"] = "House"
loc kullanmak (zincirleme indeksleme ile aynı):# Using loc plus indexing is the same as chained indexing
df.loc[df["propertyType"] == "Not Specified"]["propertyType"] = "House"
Bu iki örnek, insanları genellikle yanıltır çünkü yaygın bir yanlış kanı, loc olduğu sürece orijinal veriyi değiştirdiğimizdir. Bu yanlıştır. Değerin orijinal DataFrame’e atandığından emin olmanın tek yolu, veriye erişirken ayrı bir indeksleme kullanmadan tek bir loc ile doğrudan atama yapmaktır.
copy()DataFrame’in bir kopyası üzerinde çalıştığımızdan emin olmak istediğimizde .copy() yöntemini kullanmalıyız.
Diyelim ki mülklerin fit kare başına fiyatını analiz etmemiz istendi. Orijinal veriyi değiştirmek istemiyoruz. Amacımız, analiz sonuçlarıyla yeni bir DataFrame oluşturup başka bir ekibe göndermek.
İlk adım bazı satırları filtrelemek ve veriyi temizlemektir. Özellikle şunları yapmamız gerekir:
sizeSqFeetMax tanımlı olmayan satırları kaldırın."POA" (price on application) olduğu satırları kaldırın."£25,000,000")Yukarıdaki adımları şu kodla yapabiliriz:
# 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"])
Fit kare başına fiyatı hesaplamak için, price sütununu sizeSqFeetMax sütununa bölen sonuçlardan oluşan yeni bir sütun oluştururuz:
properties_with_size_and_price["pricePerSqFt"] = properties_with_size_and_price["price"] / properties_with_size_and_price["sizeSqFeetMax"]
Bu kodu çalıştırırsak, yine SettingWithCopyWarning alırız. Bu şaşırtıcı olmamalı çünkü açıkça properties_with_size_and_price adlı geçici bir DataFrame değişkeni oluşturup onu değiştirdik.
Orijinal DataFrame yerine verinin bir kopyasıyla çalışmak istediğimiz için, ilk satırda .copy() yöntemini kullanarak properties_with_size_and_price’ın bir görünüm değil, yeni bir DataFrame kopyası olduğundan emin olarak sorunu çözebiliriz:
properties_with_size_and_price = df[df["sizeSqFeetMax"].notna() & (df["price"] != "POA")].copy()
Yeni sütunları güvenle eklemek
Yeni sütun oluşturmak, değer atamayla aynı şekilde davranır. Kopya mı yoksa görünümle mi çalıştığımız belirsiz olduğunda pandas bir SettingWithCopyWarning yükseltir.
Verinin bir kopyasıyla çalışmak istiyorsak, .copy() yöntemini kullanarak bunu açıkça kopyalamalıyız. Sonrasında, yeni bir sütunu dilediğimiz şekilde atayabiliriz. Önceki örnekte pricePerSqFt sütununu oluştururken bunu yaptık.
Öte yandan, orijinal DataFrame’i değiştirmek istiyorsak iki durumu göz önünde bulundurmalıyız.
note sütunu ekleyebiliriz: df["notes"] = df["propertyType"].apply(lambda house_type: "Missing house type" if house_type == "Not Specified" else "")
loc indeksleyicisini kullanabiliriz. Örneğin:df.loc[df["propertyType"] == "Not Specified", "notes"] = "Missing house type"
Bu durumda, seçilmeyen satırlardaki değerler tanımsız kalacağından ilk yaklaşım tercih edilir; çünkü her satır için bir değer belirtmemize olanak tanır.
SettingWithCopyWarning HatasıŞu anda, SettingWithCopyWarning yalnızca bir uyarıdır, hata değildir. Kodumuz yine çalışır ve Pandas sadece dikkatli olmamız için bizi bilgilendirir.
Resmi Pandas belgelerine göre, SettingWithCopyWarning 3.0 sürümünden itibaren artık kullanılmayacak ve varsayılan olarak gerçek bir hata ile değiştirilecek; bu da daha sıkı kod standartlarını zorunlu kılacak.
Kodumuzun gelecekteki pandas sürümleriyle uyumlu kalmasını sağlamak için, uyarı yerine hata yükseltecek şekilde şimdiden güncellememiz önerilir.
Bu, pandas’ı içe aktardıktan sonra şu seçeneği ayarlayarak yapılır:
import pandas as pd
pd.options.mode.copy_on_write = True
Bunu mevcut koda eklemek, kodumuzdaki her belirsiz atamayla ilgilendiğimizden emin olmamızı ve pandas 3.0’a güncellediğimizde kodun çalışmaya devam etmesini sağlar.
SettingWithCopyWarning, kodumuz bir değeri değiştirdiğimizde bunun bir görünüm mü yoksa kopya mı olduğu belirsizliğine düştüğünde ortaya çıkar. Bunu, ne istediğimizi her zaman açıkça belirterek çözebiliriz:
copy() yöntemini kullanarak açıkça kopyalamalıyız.loc indeksleyicisini kullanmalı ve ara değişkenler kullanmadan veriye erişirken değeri doğrudan atamalıyız.Hata olmasa da bu uyarıyı görmezden gelmemeliyiz çünkü beklenmedik sonuçlara yol açabilir. Dahası, Pandas 3.0’dan itibaren varsayılan olarak hata olacak; bu yüzden mevcut kodumuzda pd.options.mode.copy_on_write = True ayarını etkinleştirerek kodumuzu geleceğe hazır hâle getirmeliyiz. Bu, kodun Pandas’ın gelecekteki sürümlerinde de çalışmasını sağlar.
Pandas hakkında daha fazla bilgi edinmek için şu kaynaklara göz atın:
loc kullanmak her zaman güvenlidir ve df başka bir DataFrame’den oluşturulmadığı sürece uyarı tetiklemez veya beklenmedik davranışa yol açmaz. Örneğin, df veri setini okurken oluşturduğumuz DataFrame ise, bu güvenlidir. Ancak bir ara hesaplamanın sonucuysa, yalnızca copy() yöntemiyle kopyalanmışsa güvenlidir.
warnings paketini kullanıp şu kodu ekleyebiliriz:
import warnings
warnings.simplefilter(action='ignore', category=pd.errors.SettingWithCopyWarning)
Ancak bu uyarıyı bastırmamak ya da görmezden gelmemek şiddetle tavsiye edilir; çünkü kodunuzun düşündüğünüz işi yapmıyor olabileceği anlamına gelir.
Uyarıyı geçici olarak görmezden gelmek için warnings paketini kullanıp kodumuzu şu şekilde sarmalayabiliriz:
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=pd.errors.SettingWithCopyWarning)
# Our code goes here
Ancak bu uyarıyı bastırmamak ya da görmezden gelmemek şiddetle tavsiye edilir; çünkü kodunuzun düşündüğünüz işi yapmıyor olabileceği anlamına gelir.
Yeni bir sütun eklerken uyarıyı düzeltmek, değerlere atama yaparken olduğu gibidir. Verinin bir kopyası üzerinde çalışmayı amaçlıyorsanız DataFrame’i önce kopyaladığınızdan veya loc kullandığınızdan emin olun.
Pandas’ın en güncel sürümlerinde, bu eğitimdeki uygulamaları takip etmek herhangi bir uyarıyı tetiklememelidir.
Daha eski bir sürüm kullanıyorsanız, en son kararlı sürüme güncellemenizi tavsiye ederiz. Eski sürümlerde bu uyarıyla ilgili bilinen hatalar vardır ve kodda sorun olmadığı hâlde uyarı tetiklenebilir.
Pandas sürümü güncelse, altta yatan sorun muhtemelen bariz olmayan bir zincirleme indeksleme durumudur. DataFrame’in nasıl oluşturulduğunu dikkatle gözden geçirin.
Bu kurslarla Pandas öğrenin!
Kurs
Kurs
Kurs
blog
Dario Radečić
15 dk.

blog
Abid Ali Awan
14 dk.
Eğitim
Adel Nehme
Eğitim
Kurtis Pykes
8 dk.