Kita sudah lancar memilih baris dan kolom; langkah logis berikutnya adalah mengubah nilainya. Tutorial lama biasanya menyarankan pola chained assignment seperti df["a"][0] = 99, yaitu dua akses berurutan dalam satu baris. Pada pandas 3.0 pola tersebut tidak lagi mengubah DataFrame dan justru memunculkan warning ChainedAssignmentError. Chapter ini menunjukkan perilaku barunya secara nyata, menjelaskan penyebabnya, lalu memperkenalkan pola .loc yang benar.
Perilaku Chained Assignment di pandas 3.0 #
Ekspresi df["a"][0] = 99 sebenarnya terdiri dari dua operasi terpisah. Operasi pertama, df["a"], dijalankan lebih dulu dan menghasilkan sebuah objek perantara berupa Series. Operasi kedua, [0] = 99, menulis nilai ke objek perantara tersebut, bukan langsung ke df. Karena Copy-on-Write selalu aktif di pandas 3.0, objek perantara berperilaku seperti salinan, sehingga penulisan nilai menyasar salinan dan df asli tidak berubah sama sekali. Sebagai kompensasinya, pandas mengeluarkan warning ChainedAssignmentError agar pembaca kode tahu bahwa baris tersebut tidak berpengaruh.
Mengapa Warning Muncul di stderr #
Warning ChainedAssignmentError dicatat oleh modul warnings Python dan ditampilkan ke stderr, bukan ke stdout. Stderr adalah kanal output yang terpisah dari output program, sehingga hasil print() tetap bersih meskipun ada warning. Saat menjalankan skrip di terminal, pesan lengkapnya muncul di layar berisi penjelasan “A value is being set on a copy of a DataFrame or Series through chained assignment” beserta saran memakai .loc[row_indexer, col_indexer] = value dalam satu langkah. Di Jupyter Notebook, warning yang sama tampil sebagai kotak peringatan di bawah sel. Perilaku baru ini menggantikan SettingWithCopyWarning era pandas lama, yang kini tidak muncul lagi.
Menangkap Warning Secara Deterministik #
Untuk keperluan pembelajaran, warning bisa ditangkap dengan modul warnings sehingga tercetak sebagai output program yang stabil. Pola warnings.catch_warnings(record=True) menyimpan setiap warning ke sebuah list, dan warnings.simplefilter("always") memastikan warning tersebut tidak disaring oleh Python. Script pada bagian akhir chapter memakai pola ini, lalu mencetak nama kategori warning secara eksplisit. Di pemakaian nyata kita tidak perlu menangkap warning; cukup jalankan skrip biasa dan perbaiki setiap ChainedAssignmentError yang muncul di stderr.
Pola yang Benar dengan .loc #
Pengganti chained assignment adalah satu akses .loc yang menyebut baris dan kolom sekaligus. Ekspresi df.loc[0, "a"] = 99 menulis nilai langsung ke df tanpa objek perantara, sehingga perubahan benar-benar tersimpan. Pola yang sama bekerja untuk penulisan berbasis mask: df.loc[df["b"] > 4, "b"] = 0 mengganti seluruh nilai kolom b yang di atas 4 dalam satu langkah. Penambahan kolom baru pun bisa dilakukan lewat .loc dengan mask, misalnya df.loc[df["a"] >= 2, "kategori"] = "tinggi".
Tabel berikut merangkum pola lama dan penggantinya:
| Pola chained (tidak berefek di pandas 3.0) | Pengganti satu akses |
|---|---|
df["a"][0] = 99 | df.loc[0, "a"] = 99 |
df["a"][df["a"] > 2] = 0 | df.loc[df["a"] > 2, "a"] = 0 |
df.loc[0]["a"] = 99 | df.loc[0, "a"] = 99 |
Aturan Praktis Menghindari Chained Indexing #
- Lakukan seleksi dan penulisan dalam satu operasi
.locatau.iloc, tidak pernah dua akses berurutan. - Perlakukan setiap warning
ChainedAssignmentErrordi stderr sebagai tugas perbaikan, karena baris terkait tidak mengubah apa pun. - Bila memang butuh salinan kerja, panggil
.copy()secara eksplisit lalu ubah salinan tersebut. - Ingat bahwa hasil seleksi apa pun pada pandas 3.0 berperilaku seperti salinan; jangan mengharapkan perubahan mengalir kembali ke DataFrame asal.
Contoh Lengkap dan Bedah Kode #
Skrip berikut membandingkan kedua pola pada DataFrame yang sama dan menangkap warning dari pola pertama.
import warnings
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
with warnings.catch_warnings(record=True) as catatan:
warnings.simplefilter("always")
df["a"][0] = 99
print("Setelah df['a'][0] = 99 (chained assignment):")
print(df)
print()
if catatan:
print("Warning tercatat:", catatan[0].category.__name__)
else:
print("Tidak ada warning tercatat.")
print()
df.loc[0, "a"] = 99
print("Setelah df.loc[0, 'a'] = 99:")
print(df)Output yang Dihasilkan:
Setelah df['a'][0] = 99 (chained assignment):
a b
0 1 4
1 2 5
2 3 6
Warning tercatat: ChainedAssignmentError
Setelah df.loc[0, 'a'] = 99:
a b
0 99 4
1 2 5
2 3 6Mari kita telaah baris demi baris:
- Baris 5 (
df = pd.DataFrame({...})): DataFrame dua kolom dengan index default 0 sampai 2 disiapkan. - Baris 7-9 (
df["a"][0] = 99): chained assignment dijalankan di dalam blokcatch_warnings, sehingga warningChainedAssignmentErrortersimpan ke listcatatanalih-alih tampil di stderr. - Baris 11-13: DataFrame dicetak dan kolom
amasih berisi1, 2, 3— nilai 99 tidak pernah masuk, bukti bahwa pola chained tidak berefek. - Baris 15-18: list
catatandiperiksa, dan kategori warning yang tercatat adalahChainedAssignmentError. - Baris 21-23 (
df.loc[0, "a"] = 99): satu akses.locmenulis nilai ke baris 0 koloma, dan cetakan terakhir menunjukkan99sudah tersimpan didf.
Pola .loc inilah yang harus dipakai setiap kali kita mengubah sebagian data. Dengan fondasi seleksi dan penulisan yang aman ini, Section berikutnya tentang manipulasi data — menambah kolom, mengganti nama, dan menyusun ulang tabel — bisa kita jalani tanpa jebakan tersembunyi. Aturan yang membuat pola ini menjadi satu-satunya jalur dibahas penuh pada chapter Copy-on-Write di section Advanced Pandas.
Referensi resmi: Copy-on-Write dan What’s new in pandas 3.0.0 .