Seleksi dengan loc

Seleksi baris dan kolom berbasis label pada loc, termasuk sifat inklusif slicing.

Daftar isi

Seleksi berbasis label menunjuk baris dan kolom lewat nama yang tertulis pada indeks, dan alat utamanya adalah df.loc[baris, kolom]. Topik ini membahas pola dasar loc, pembuatan label baris yang bermakna dengan set_index, sifat slice label yang inklusif di kedua ujung, pemilihan baris dengan mask boolean, dan penulisan nilai yang benar pada pandas 3.x. Setelah membaca, pemilihan dan pengubahan nilai dapat dilakukan dengan satu bentuk sintaks yang konsisten pada dataset log sensor tiga ruangan.

Pola dasar df.loc[baris, kolom]#

loc menerima dua pemilih yang dipisah koma, yaitu pemilih baris di depan dan pemilih kolom di belakang, dan keduanya diinterpretasikan sebagai label, bukan posisi. Label baris pada dataset bawaan generator hanya berupa angka 0 sampai 95 yang kurang bermakna, sehingga langkah pertama yang layak adalah menjadikan kolom waktu sebagai indeks dengan set_index("waktu"). Setelah itu setiap baris berlabel stempel waktu bacaan, dan label itu dapat ditulis langsung pada loc.

python Menjadikan kolom waktu sebagai label baris
import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
n = 96
df = pd.DataFrame({
    "waktu": pd.date_range("2026-01-05 07:00", periods=n, freq="15min"),
    "ruang": rng.choice(["Lab A", "Lab B", "Ruang Arsip"], n, p=[0.4, 0.35, 0.25]),
    "suhu_c": np.round(rng.normal(24, 1.5, n), 1),
    "lembap_pct": np.round(rng.normal(60, 5, n), 1),
    "status_sensor": rng.choice(["normal", "kalibrasi", "rusak"], n, p=[0.85, 0.10, 0.05]),
})
df.to_csv("sensor_log.csv", index=False)  # disimpan agar blok berikutnya cukup membaca berkas ini
dfw = df.set_index("waktu")
print(dfw.columns.tolist())
text Keluaran
['ruang', 'suhu_c', 'lembap_pct', 'status_sensor']

Kolom waktu berpindah dari daftar kolom menjadi label indeks. Satu label baris menghasilkan Series sepanjang kolom, sedangkan list label menghasilkan DataFrame dengan baris dan kolom yang dipilih.

python Mengambil satu baris dan beberapa baris dengan label
import pandas as pd

dfw = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
print(dfw.loc["2026-01-05 07:15"])
print(dfw.loc[["2026-01-05 07:00", "2026-01-05 07:15"], ["ruang", "suhu_c"]])
text Keluaran
ruang             Lab B
suhu_c             21.8
lembap_pct         59.1
status_sensor    normal
Name: 2026-01-05 07:15:00, dtype: object
                           ruang  suhu_c
waktu
2026-01-05 07:00:00  Ruang Arsip    21.5
2026-01-05 07:15:00        Lab B    21.8

Baris tunggal dicetak sebagai Series bertipe object karena isinya mencampur teks dan angka, sedangkan pemilihan dengan list label dan list kolom menghasilkan tabel kecil berlabel waktu. Bentuk df.loc[label, kolom] inilah pola yang dipakai di seluruh modul ini.

Slice label inklusif di kedua ujung#

Slice pada loc diinterpretasikan sebagai label, dan kedua ujungnya ikut terpilih. Sifat ini berbeda dari slice posisi pada iloc yang ujung atasnya dikeluarkan, sehingga berpindah dari iloc ke loc tanpa menyesuaikan batas akan menggeser isi hasil. Slice label juga bisa ditulis dengan nilai yang belum menjadi tipe indeksnya, misalnya string stempel waktu pada indeks bertipe tanggal, karena pandas mengonversinya sebelum membandingkan.

python Slice label waktu dari 07:00 sampai 07:45
import pandas as pd

dfw = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
porsi = dfw.loc["2026-01-05 07:00":"2026-01-05 07:45", ["ruang", "suhu_c"]]
print(porsi)
print("jumlah baris:", len(porsi))
text Keluaran
                           ruang  suhu_c
waktu
2026-01-05 07:00:00  Ruang Arsip    21.5
2026-01-05 07:15:00        Lab B    21.8
2026-01-05 07:30:00  Ruang Arsip    22.0
2026-01-05 07:45:00        Lab B    22.5
jumlah baris: 4

Rentang 07:00 sampai 07:45 sepanjang 45 menit menghasilkan empat baris karena kedua ujung ikut, yaitu 07:00, 07:15, 07:30, dan 07:45. Pada iloc dengan logika eksklusif, rentang sepanjang empat langkah harus ditulis 0:4 untuk hasil yang sama. Keputusan desain ini memudahkan pemilihan berdasar nilai label yang terbaca manusia, tetapi menuntut kejelian saat kode dipindah antar alat.

Memilih baris dengan mask#

loc menerima mask boolean sebagai pemilih baris, yaitu Series bertipe bool sepanjang data yang nilainya menyatakan baris mana yang lolos. Kombinasi df.loc[mask, daftar_kolom] menjadi bentuk paling terarah untuk penyaringan karena baris dan kolom yang diinginkan dinyatakan dalam satu panggilan. Topik Indeks Boolean membahas pembentukan mask secara lengkap, dan di sini cukup satu mask perbandingan sederhana.

python Menyaring baris dengan suhu di atas 25 derajat
import pandas as pd

dfw = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
mask = dfw["suhu_c"] > 25
print(dfw.loc[mask, ["ruang", "suhu_c"]].head(5))
print("baris lolos:", mask.sum())
text Keluaran
                           ruang  suhu_c
waktu
2026-01-05 08:45:00  Ruang Arsip    25.9
2026-01-05 09:15:00        Lab B    25.1
2026-01-05 10:30:00        Lab B    25.3
2026-01-05 13:00:00  Ruang Arsip    26.4
2026-01-05 14:15:00        Lab B    26.0
baris lolos: 21

Dari 96 bacaan, 21 baris memiliki suhu di atas 25 derajat dan baris-baris itu tampil berlabel waktu. Mask yang sama dapat dipakai ulang untuk beberapa seleksi berbeda, sehingga menyimpannya ke variabel bernama lebih hemat daripada menulis ulang perbandingannya.

Penulisan nilai pada pandas 3.x dilakukan lewat satu panggilan df.loc[baris, kolom] = nilai, baik barisnya label tunggal, slice, maupun mask. Bentuk ini menulis langsung pada DataFrame yang dirujuk, sehingga perubahan pasti terjadi. Kasus nyata pada dataset adalah bacaan dari sensor berstatus rusak yang tidak dipercaya dan perlu ditandai sebagai nilai hilang.

python Menandai bacaan sensor rusak sebagai nilai hilang
import numpy as np
import pandas as pd

df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
df.loc[df["status_sensor"] == "rusak", "suhu_c"] = np.nan
print(df.loc[df["suhu_c"].isna(), ["ruang", "suhu_c", "status_sensor"]])
text Keluaran
    ruang  suhu_c status_sensor
43  Lab A     NaN         rusak
87  Lab B     NaN         rusak
89  Lab B     NaN         rusak

Tiga baris berstatus rusak kini bertanda NaN pada kolom suhu_c, dan perubahan itu benar-benar terjadi pada tabel. Bandingkan dengan pola chained assignment, yakni penulisan lewat dua tahap seleksi yang dirangkai, yang tidak pernah berhasil pada pandas 3.x.

python Chained assignment tidak mengubah tabel asal
import warnings
import numpy as np
import pandas as pd

df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
with warnings.catch_warnings(record=True) as terekam:
    warnings.simplefilter("always")
    df[df["status_sensor"] == "rusak"]["suhu_c"] = np.nan
print("baris rusak bertanda NaN:", df.loc[df["status_sensor"] == "rusak", "suhu_c"].isna().sum())
print("peringatan:", terekam[0].category.__name__)
print(str(terekam[0].message).splitlines()[0])
text Keluaran
baris rusak bertanda NaN: 0
peringatan: ChainedAssignmentError
A value is being set on a copy of a DataFrame or Series through chained assignment.

Ekspresi df[mask]["suhu_c"] menghasilkan salinan sementara karena Copy-on-Write, sehingga penugasan pada tahap kedua hanya mengubah salinan itu dan jumlah baris yang ditandai tetap nol. pandas memperingatkan lewat ChainedAssignmentError bahwa nilai tidak diterapkan, dan pesannya bahkan menyarankan bentuk loc sebagai perbaikannya. Pada pandas 2.x pola yang sama dulu memunculkan SettingWithCopyWarning, sehingga kode lama yang bergantung pada peringatan itu perlu ditinjau ulang saat bermigrasi.

Kesalahan umum#

Kesalahan pertama adalah menuliskan slice loc dengan asumsi eksklusif seperti iloc, sehingga baris ujung atas hilang dari hasil. Perbaikannya adalah menambah satu langkah label pada ujung atas, atau menguji dulu dengan len seperti pada contoh empat baris di atas. Kesalahan kedua adalah memanggil label yang tidak ada, dan pesan KeyError-nya menyebut label persis seperti yang ditulis.

python KeyError untuk label yang tidak ada pada indeks
import pandas as pd

dfw = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
try:
    dfw.loc["2026-01-05 06:00"]
except KeyError as e:
    print(type(e).__name__, str(e))
text Keluaran
KeyError '2026-01-05 06:00'

Perbaikannya adalah memeriksa keberadaan label dengan "2026-01-05 06:00" in dfw.index sebelum mengambilnya, atau memakai slice bila yang diinginkan adalah rentang terdekat. Kesalahan ketiga adalah chained assignment yang sudah didemokan di atas, yakni df[mask]["kolom"] = nilai dan df["kolom"][0] = nilai, yang keduanya tidak mengubah tabel asal. Selalu rangkai pemilih baris dan kolom dalam satu pasangan kurung siku milik loc.

Ringkasan#

  • df.loc[baris, kolom] memilih berdasarkan label indeks dan nama kolom, dengan label tunggal, list, slice, maupun mask boolean sebagai pemilih baris.
  • Slice loc inklusif di kedua ujung, sehingga rentang label yang terbaca manusia menghasilkan baris ujung atas yang ikut terpilih.
  • set_index("waktu") mengubah kolom menjadi label baris yang bermakna dan mengeluarkannya dari daftar kolom.
  • Penulisan nilai yang sah pada pandas 3.x adalah df.loc[mask, kolom] = nilai, sedangkan pola dirangkai hanya mengubah salinan dan memunculkan peringatan ChainedAssignmentError.

Referensi#