Penyaringan dengan query

Penyaringan berbasis string pada query serta pertukaran keterbacaannya.

Daftar isi

Penyaringan dengan query mengekspresikan kondisi baris sebagai satu string ekspresi, misalnya df.query("suhu_c > 25"), sehingga gabungan beberapa syarat terbaca seperti kalimat logika. Topik ini membahas sintaks dasar query pada dataset log sensor tiga ruangan, penggunaan variabel python melalui tanda @, pertimbangan kapan query lebih tepat daripada indeks boolean, dan kesalahan penulisan yang paling sering muncul. Setelah membaca, penyaringan berbasis string dapat ditulis dengan tanda kutip yang benar dan dipilih secara sadar di antara dua gaya penyaringan yang tersedia.

Sintaks dasar query#

query menerima string yang memuat ekspresi logika, dan nama kolom ditulis langsung tanpa tanda kutip maupun tanda $, sedangkan nilai teks di dalam ekspresi tetap membutuhkan tanda kutip sendiri. Konjungsi and, or, dan not sah di dalam string ekspresi, berbeda dengan indeks boolean yang mewajibkan &, |, dan ~. Dataset modul ini kembali dibangun oleh generator deterministik yang sama.

python Membangun dataset log sensor dan menyimpannya ke CSV
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
print(df.shape)
text Keluaran
(96, 5)

Blok berikut menyaring bacaan panas pada Lab A. Baris pd.options.compute.use_numexpr = False menonaktifkan akselerasi numexpr dan ditulis pada setiap contoh query karena lingkungan contoh memasang numexpr yang lebih tua daripada versi minimum yang didukung pandas 3.1, sehingga tanpa baris itu pandas menampilkan peringatan versi pada setiap proses baru. Pada instalasi biasa dengan numexpr terkini, baris tersebut tidak diperlukan.

python Query satu kondisi dan gabungan dua kondisi
import pandas as pd

pd.options.compute.use_numexpr = False  # numexpr lingkungan contoh lebih tua dari minimum pandas 3.1
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
panas_lab_a = df.query("suhu_c > 25 and ruang == 'Lab A'")
print(panas_lab_a[["waktu", "ruang", "suhu_c"]])
text Keluaran
                 waktu  ruang  suhu_c
32 2026-01-05 15:00:00  Lab A    26.2
43 2026-01-05 17:45:00  Lab A    25.3
68 2026-01-06 00:00:00  Lab A    27.2
70 2026-01-06 00:30:00  Lab A    25.3

Empat baris memenuhi kedua syarat sekaligus, dan perhatikan penandaan kutipnya, yaitu kutip ganda untuk string python dan kutip tunggal untuk nilai 'Lab A' di dalamnya. Nilai angka ditulis apa adanya, sedangkan nama kolom seperti suhu_c dikenali dari kolom tabel tanpa deklarasi apa pun.

Di dalam satu string ekspresi, kolom juga dapat dihitung dan dibandingkan langsung dengan kolom lain, misalnya lembap_pct - suhu_c > 35 untuk selisih kelembapan terhadap suhu, atau suhu_c < lembap_pct untuk perbandingan dua kolom tanpa konstanta apa pun. Kemampuan ini memperluas penyaringan dari sekadar ambang tetap menjadi hubungan antar kolom, dan semuanya tetap ditulis dalam satu baris string yang sama.

Variabel python dengan @nama#

Nilai yang sudah tersimpan pada variabel python dapat dipakai di dalam string ekspresi lewat tanda @ di depan namanya. Tanpa @, nama itu dicari sebagai kolom atau variabel di dalam lingkungan ekspresi, bukan di lingkungan program, dan pencarian itu berakhir error. Bentuk @ menjaga ambang batas tetap satu sumber kebenaran, misalnya ambang suhu yang ditetapkan sekali di bagian atas skrip.

python Ambang suhu disimpan di variabel lalu dipakai query
import pandas as pd

pd.options.compute.use_numexpr = False  # numexpr lingkungan contoh lebih tua dari minimum pandas 3.1
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
batas = 25
panas = df.query("suhu_c > @batas")
print("query @batas :", len(panas))
print("indeks boolean:", len(df.loc[df["suhu_c"] > batas]))
text Keluaran
query @batas : 21
indeks boolean: 21

Kedua gaya menghasilkan 21 baris yang sama persis karena ekspresinya setara. Variabel yang dirujuk tanpa @ berakhir UndefinedVariableError, dan bentuk error itu diperlihatkan pada bagian Kesalahan umum.

Memilih antara query dan indeks boolean#

query dan indeks boolean menghasilkan baris yang identik untuk ekspresi yang setara, sehingga pilihannya adalah soal keterbacaan dan bentuk kondisi yang tersedia. query unggul bila kondisinya banyak dan bertuliskan perbandingan antar kolom, karena string ekspresinya pendek tanpa tanda kurung per kondisi. Indeks boolean lebih tepat bila mask perlu dipakai ulang, dihitung, atau dibentuk dari hasil metode seperti isin, between, dan aksesor .str, karena mask adalah Series biasa yang dapat disimpan dan digabung di luar pemanggilan seleksi.

python Ekspresi or pada query dibandingkan mask boolean
import pandas as pd

pd.options.compute.use_numexpr = False  # numexpr lingkungan contoh lebih tua dari minimum pandas 3.1
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
lewat_query = df.query("suhu_c < 22 or suhu_c > 26")
lewat_mask = df.loc[(df["suhu_c"] < 22) | (df["suhu_c"] > 26)]
print(len(lewat_query), len(lewat_mask))
print(lewat_query.equals(lewat_mask))
text Keluaran
18 18
True

Delapan belas baris berada di luar rentang 22 sampai 26 derajat menurut kedua gaya, dan metode equals() menyatakan keduanya identik termasuk urutan barisnya. Hasil yang sama ini bukan kebetulan, karena query pada akhirnya mengevaluasi ekspresi menjadi mask boolean yang sama, dengan mesin ekspresi pandas dan pustaka numexpr menangani perhitungannya bila pustaka itu tersedia dan versinya didukung.

Satu perbedaan praktis perlu diingat, yaitu string ekspresi tidak diperiksa linter python karena bukan kode python, sehingga kesalahan nama kolom baru terasa saat eksekusi, sedangkan mask boolean ditulis dengan nama kolom python biasa yang diperiksa editor. Karena itu, query paling menguntungkan pada tahap eksplorasi, ketika banyak kondisi teks perlu dicoba dan diubah-ubah. Indeks boolean lebih tepat pada skrip yang stabil, tempat mask dipakai ulang untuk beberapa seleksi, dihitung jumlah True-nya, atau dibentuk dari hasil metode seperti isin, between, dan aksesor .str yang tidak punya padanan di dalam string ekspresi.

Kesalahan umum#

Kesalahan pertama adalah merujuk variabel python tanpa @, yang dicari sebagai variabel ekspresi dan berakhir UndefinedVariableError. Kesalahan kedua adalah menulis nilai teks tanpa tanda kutip, sehingga parser ekspresi menolaknya dengan SyntaxError. Keduanya diperlihatkan berdampingan.

python Variabel tanpa @ dan nilai teks tanpa kutip
import pandas as pd

pd.options.compute.use_numexpr = False  # numexpr lingkungan contoh lebih tua dari minimum pandas 3.1
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
batas = 25
try:
    df.query("suhu_c > batas")
except Exception as e:
    print(type(e).__name__, str(e))
try:
    df.query("ruang == Lab A")
except Exception as e:
    print(type(e).__name__, str(e))
text Keluaran
UndefinedVariableError name 'batas' is not defined
SyntaxError invalid syntax (<unknown>, line 1)

Perbaikan untuk keduanya sudah tampak pada contoh yang benar, yaitu @batas dan 'Lab A'. Kesalahan ketiga adalah memakai tanda kutip yang sama untuk string python dan nilai di dalamnya, misalnya "ruang == "Lab A"", yang memutus string python lebih dahulu dan berakhir error sintaks pada baris itu sendiri. Pilih tanda kutip luar dan dalam yang berbeda. Kesalahan keempat adalah menulis query pada kolom yang namanya mengandung spasi, karena parser membaca nama tersebut sebagai dua istilah. Nama seperti itu harus dibungkus backtick di dalam string ekspresi.

python Kolom dengan spasi dibungkus backtick
import pandas as pd

pd.options.compute.use_numexpr = False  # numexpr lingkungan contoh lebih tua dari minimum pandas 3.1
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"])
df_sp = df.rename(columns={"suhu_c": "suhu celcius"})
print(len(df_sp.query("`suhu celcius` > 26")))
text Keluaran
9

Sembilan baris memiliki suhu di atas 26 derajat menurut kolom yang kini bernama suhu celcius. Larangannya berlaku dua arah, yaitu nama kolom tanpa spasi tidak perlu backtick dan penambahan spasi pada nama kolom sebaiknya dihindari sejak awal agar query maupun akses kolom tetap ringkas.

Ringkasan#

  • df.query("ekspresi") mengekspresikan kondisi baris sebagai string, dengan and, or, dan not sah di dalamnya.
  • Variabel python dirujuk dengan tanda @, sedangkan nama tanpa @ dicari di lingkungan ekspresi dan berakhir UndefinedVariableError.
  • Nilai teks di dalam ekspresi membutuhkan tanda kutip yang berbeda dari kutip string luarnya, dan kolom bernama spasi dibungkus backtick.
  • query menang pada gabungan kondisi yang panjang, sedangkan indeks boolean lebih tepat bila mask dipakai ulang atau dibentuk dari hasil metode.

Referensi#