Seleksi dan penyaringan

Mengambil subset data dengan loc, iloc, dan masker boolean sesuai kebutuhan analisis.

Daftar isi

Analisis jarang memproses seluruh baris dan kolom sekaligus. Topik ini membahas tiga cara mengambil subset data pada pandas, yaitu loc untuk seleksi berbasis label, iloc untuk seleksi berbasis posisi, dan masker boolean, yakni deret nilai True dan False yang digunakan untuk menyaring baris berdasarkan syarat. Setelah topik ini, baris dan kolom yang relevan dapat diambil dengan tepat, dan kesalahan seleksi yang paling sering terjadi dapat dihindari.

Data contoh dan index#

Setiap baris pada DataFrame menempel pada sebuah label yang disebut index, yakni penanda baris yang digunakan untuk seleksi. Tanpa pengaturan, labelnya berupa angka mulai dari nol. Untuk memperjelas perbedaan antara loc dan iloc, data contoh pada topik ini menggunakan label huruf, yaitu s1 sampai s6.

python Menyiapkan data nilai dengan index label
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

print(nilai)
text Keluaran
     nama kelas  matematika  bahasa
s1    Ali    7A          78      82
s2   Budi    7A          85      79
s3  Citra    7B          90      88
s4   Dewi    7B          76      81
s5    Eka    8A          88      90
s6  Fajar    8A          92      84

Label index inilah yang digunakan loc, sedangkan iloc menggunakan posisi urut baris. Pada data yang dimuat dari berkas, labelnya biasanya berupa angka, sehingga label dan posisinya kebetulan identik. Data contoh ini sengaja membuat keduanya berbeda agar perbedaan mekanismenya terlihat.

Seleksi dengan loc#

loc menerima label. Ekspresi nilai.loc["s2"] mengambil satu baris berlabel s2 dan mengembalikannya sebagai Series, sedangkan nilai.loc["s2", "matematika"] mengambil satu sel pada pertemuan baris s2 dan kolom matematika. Pemotongan rentang dengan loc bersifat inklusif, sehingga batas akhirnya ikut diambil.

python Seleksi baris dan sel dengan loc
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

print(nilai.loc["s2"])
print()
print(nilai.loc["s2", "matematika"])
print()
print(nilai.loc["s1":"s3"])
text Keluaran
nama          Budi
kelas           7A
matematika      85
bahasa          79
Name: s2, dtype: object

85

     nama kelas  matematika  bahasa
s1    Ali    7A          78      82
s2   Budi    7A          85      79
s3  Citra    7B          90      88

Rentang s1 sampai s3 menghasilkan tiga baris, berbeda dengan pemotongan list pada Python yang mengabaikan batas akhirnya. Perilaku inklusif ini berlaku karena batas rentang loc adalah label, bukan posisi. Selain label tunggal, loc juga menerima daftar label, misalnya nilai.loc[["s1", "s4"]] untuk mengambil dua baris yang tidak berurutan, dan nama kolom dapat ditulis pada dimensi keduanya untuk membatasi kolom yang diambil.

Seleksi dengan iloc#

iloc menerima posisi, yaitu urutan baris mulai dari nol. Ekspresi nilai.iloc[1] mengambil baris kedua, dan hasilnya sama dengan nilai.loc["s2"] karena baris kedua berlabel s2 pada data contoh ini. Pemotongan rentang dengan iloc mengikuti konvensi Python dan bersifat eksklusif, sehingga batas akhirnya tidak ikut diambil.

python Seleksi baris dan blok data dengan iloc
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

print(nilai.iloc[1])
print()
print(nilai.iloc[:3, 1:3])
text Keluaran
nama          Budi
kelas           7A
matematika      85
bahasa          79
Name: s2, dtype: object

   kelas  matematika
s1    7A          78
s2    7A          85
s3    7B          90

Rentang :3 pada dimensi baris berarti posisi 0, 1, dan 2, sedangkan rentang 1:3 pada dimensi kolom berarti kolom kedua dan ketiga, yaitu kelas dan matematika. Dengan demikian, iloc[:3, 1:3] mengambil blok data tiga baris kali dua kolom tanpa kolom nama dan bahasa. Aturan memilihnya sederhana, yaitu loc bila label barisnya diketahui dan iloc bila posisinya yang diketahui, misalnya lima baris pertama atau baris terakhir.

Penyaringan dengan masker boolean#

Perbandingan pada satu kolom menghasilkan masker boolean, yaitu deret nilai True dan False dengan panjang yang sama dengan jumlah baris. Masker yang diberikan di dalam kurung siku memilih baris yang bernilai True.

python Membuat masker dan menyaring baris dengannya
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

masker = nilai["matematika"] >= 80
print(masker)
print()
print(nilai[masker])
text Keluaran
s1    False
s2     True
s3     True
s4    False
s5     True
s6     True
Name: matematika, dtype: bool

     nama kelas  matematika  bahasa
s2   Budi    7A          85      79
s3  Citra    7B          90      88
s5    Eka    8A          88      90
s6  Fajar    8A          92      84

Keluaran pertama adalah maskernya sendiri, yaitu enam nilai boolean yang menyatakan baris dengan nilai matematika minimal 80. Keluaran kedua adalah hasil penyaringannya, berupa empat baris yang labelnya tidak berurutan karena baris s1 dan s4 terbuang. Label tetap asli, sehingga jejak baris asalnya tidak hilang. Penyaringan dengan beberapa syarat menggabungkan masker menggunakan operator & untuk syarat “dan” dan | untuk syarat “atau”, dengan setiap syarat diberi tanda kurung.

python Menggabungkan dua syarat penyaringan
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

pilihan = (nilai["kelas"] == "7A") & (nilai["matematika"] >= 80)
print(nilai[pilihan])
text Keluaran
    nama kelas  matematika  bahasa
s2  Budi    7A          85      79

Tanda kurung wajib karena operator & memiliki urutan pengerjaan yang lebih tinggi daripada perbandingan ==. Tanpa kurung, Python menghitung "7A" & nilai["matematika"] terlebih dahulu dan memunculkan error. Syarat gabungan juga dapat dipadukan dengan loc untuk membatasi kolomnya sekaligus, misalnya nilai.loc[pilihan, ["nama", "matematika"]], karena loc menerima masker pada dimensi barisnya.

Kesalahan umum#

Kesalahan pertama adalah menggunakan kata kunci and dan or dari Python pada masker. Kata kunci tersebut menuntut nilai boolean tunggal, sedangkan masker berisi banyak nilai sekaligus, dan permintaan itu tidak dapat dijawab.

python Error yang muncul ketika and digunakan pada masker
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

try:
    pilihan = (nilai["kelas"] == "7A") and (nilai["matematika"] >= 80)
except ValueError as e:
    print("ValueError:", e)
text Keluaran
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Pesan errornya menyebut kata “ambiguous” karena benar atau salahnya sebuah deret nilai memang tidak terdefinisi. Ganti kata kunci tersebut dengan operator & dan | beserta tanda kurung per syarat.

Kesalahan kedua adalah penulisan berantai untuk mengubah data. Ekspresi nilai[nilai["kelas"] == "8A"]["bahasa"] = 90 terlihat wajar, tetapi pandas tidak menjamin perubahan itu diterapkan pada data asli, dan pandas menampilkan peringatan SettingWithCopyWarning ketika pola ini digunakan. Cara yang dijamin adalah satu panggilan loc dengan masker dan nama kolom.

python Mengubah sel dengan syarat melalui loc
import pandas as pd

nilai = pd.DataFrame(
    {
        "nama": ["Ali", "Budi", "Citra", "Dewi", "Eka", "Fajar"],
        "kelas": ["7A", "7A", "7B", "7B", "8A", "8A"],
        "matematika": [78, 85, 90, 76, 88, 92],
        "bahasa": [82, 79, 88, 81, 90, 84],
    },
    index=["s1", "s2", "s3", "s4", "s5", "s6"],
)

salinan = nilai.copy()
salinan.loc[salinan["kelas"] == "8A", "bahasa"] = 90
print(salinan)
text Keluaran
     nama kelas  matematika  bahasa
s1    Ali    7A          78      82
s2   Budi    7A          85      79
s3  Citra    7B          90      88
s4   Dewi    7B          76      81
s5    Eka    8A          88      90
s6  Fajar    8A          92      90

Pola di atas menyalin seluruh tabel lebih dahulu, lalu mengubah kolom bahasa untuk baris kelas 8A pada salinan itu. Apabila subset memang dimaksudkan sebagai tabel mandiri, tambahkan .copy() pada akhir penyaringannya, misalnya nilai[nilai["kelas"] == "8A"].copy(), sehingga hasilnya terlepas dari data aslinya dan bebas dari peringatan tersebut.

Ringkasan#

  • loc bekerja dengan label dan rentangnya inklusif, sedangkan iloc bekerja dengan posisi dan rentangnya eksklusif.
  • Masker boolean memilih baris berdasarkan syarat, digabung dengan & dan | serta tanda kurung per syarat, dan label barisnya tetap asli setelah penyaringan.
  • Pengubahan data bersyarat dilakukan melalui satu panggilan loc dengan masker dan nama kolom, bukan penulisan berantai.

Referensi#