Topik ini membahas DatetimeIndex, yaitu index baris yang bertipe datetime, beserta cara penyaringannya pada dataset log sensor tiga ruangan. Kolom waktu dijadikan index dengan set_index, lalu baris diambil menurut rentang label, string parsial untuk satu hari atau satu jam, dan jendela jam yang berulang dengan between_time. Setelah membaca, pemilihan baris berdasarkan waktu dapat dilakukan tanpa menyaring kolom satu per satu.
Menjadikan kolom waktu sebagai index#
Method set_index("waktu") menjadikan kolom waktu sebagai label baris dan menghasilkan DatetimeIndex, yaitu index yang menyimpan nilai datetime. Posisi index memberi kolom waktu perlakuan khusus, karena pandas mengenali index bertipe datetime dan menyediakan penyaringan berbasis waktu yang tidak tersedia untuk kolom biasa. Konversi teks ke datetime dilakukan terlebih dahulu lewat parameter parse_dates, sebagaimana dibahas pada topik Konversi datetime, kemudian barulah set_index dipanggil.
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) # dataset bersama untuk seluruh modul
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
print(df.head(3))
print(type(df.index).__name__) ruang suhu_c lembap_pct status_sensor
waktu
2026-01-05 07:00:00 Ruang Arsip 21.5 68.6 normal
2026-01-05 07:15:00 Lab B 21.8 59.1 normal
2026-01-05 07:30:00 Ruang Arsip 22.0 58.1 normal
DatetimeIndexKeluaran menunjukkan nama waktu berpindah ke posisi label baris di sisi kiri tabel, dan tiga baris pertama berlabel 07.00 sampai 07.30. Pemeriksaan type(df.index).__name__ menegaskan bahwa indexnya kini DatetimeIndex, bukan index angka bawaan. Seluruh penyaringan pada topik ini memakai bentuk tabel yang sama, sehingga blok berikutnya cukup membaca ulang berkas dan memanggil set_index sebelum menyaring.
Penyaringan rentang dengan loc#
Method loc menerima dua label waktu yang dipisah titik dua untuk mengambil seluruh baris pada rentang tersebut. Bentuknya df.loc["2026-01-05 07:00":"2026-01-05 08:00"], dan teksnya ditulis dalam format ISO seperti nilai datetime itu sendiri. Seleksi ini dapat dipadukan dengan seleksi kolom, sehingga tabel hasilnya hanya memuat kolom yang benar-benar dibutuhkan.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
sel = df.loc["2026-01-05 07:00":"2026-01-05 08:00", ["ruang", "suhu_c"]]
print(sel) 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
2026-01-05 08:00:00 Lab A 24.6Keluaran memuat lima baris yang berjarak lima belas menit, mulai dari 07.00 sampai 08.00. Kedua ujung rentang ikut terambil, sehingga baris berlabel 07.00 dan 08.00 sama-sama ada pada hasil. Sifat inklusif ini berbeda dengan slicing list Python yang mengabaikan batas kanannya, dan perbedaan itu penting diingat ketika menghitung jumlah baris yang diharapkan dari sebuah rentang.
String parsial untuk satu hari atau satu jam#
String parsial adalah teks tanggal yang dipotong sebagian, dan pandas mengambil semua baris yang jatuh pada periode yang tersirat dari potongan itu. Bentuk df.loc["2026-01-05"] mengambil satu hari penuh, sedangkan df.loc["2026-01-05 07"] mengambil satu jam penuh karena jamnya ikut dinyatakan. Penyaringan ini hanya berlaku pada DatetimeIndex, sehingga konversi pada topik Konversi datetime menjadi syaratnya.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
sehari = df.loc["2026-01-05"]
print("baris untuk satu hari:", len(sehari))
print(sehari.head(3))
sejam = df.loc["2026-01-05 07"]
print("baris untuk satu jam:", len(sejam))
print(sejam[["ruang", "suhu_c"]])baris untuk satu hari: 68
ruang suhu_c lembap_pct status_sensor
waktu
2026-01-05 07:00:00 Ruang Arsip 21.5 68.6 normal
2026-01-05 07:15:00 Lab B 21.8 59.1 normal
2026-01-05 07:30:00 Ruang Arsip 22.0 58.1 normal
baris untuk satu jam: 4
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.5Keluaran menunjukkan 68 baris untuk teks satu hari, yaitu seluruh bacaan dari 07.00 sampai 23.45 pada 5 Januari, dan 4 baris untuk teks satu jam, yaitu bacaan 07.00 sampai 07.45. Log berjalan dari pukul 07.00 pada 5 Januari hingga 06.45 pada 6 Januari, sehingga satu hari kalender tidak selalu berisi 96 bacaan. Hubungan teks dan periodenya konsisten, yaitu semakin panjang teksnya, semakin sempit periode yang tercakup.
between_time untuk jendela jam harian#
Method between_time("08:00", "09:00") mengambil baris pada jendela jam yang berulang setiap hari, dengan kedua ujung jendela ikut dihitung secara bawaan. Method ini bekerja pada komponen jam dari index, sehingga tanggalnya boleh berbeda asalkan jamnya jatuh di dalam jendela. Bentuk ini cocok untuk pertanyaan seperti bacaan pada jam operasional tertentu, tanpa perlu menyusun rentang tanggal satu per satu.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
print(df.between_time("08:00", "09:00")[["ruang", "suhu_c"]]) ruang suhu_c
waktu
2026-01-05 08:00:00 Lab A 24.6
2026-01-05 08:15:00 Ruang Arsip 22.6
2026-01-05 08:30:00 Ruang Arsip 23.4
2026-01-05 08:45:00 Ruang Arsip 25.9
2026-01-05 09:00:00 Lab A 23.5Keluaran memuat lima baris yang seluruhnya berasal dari 5 Januari, yaitu bacaan 08.00 sampai 09.00. Tidak ada baris dari 6 Januari karena log pada hari itu berhenti pukul 06.45, sehingga jendela 08.00 sampai 09.00 tidak menemui waktunya. Batas atas jendela ikut terambil sebagaimana batas bawahnya, dan perhatikan bahwa between_time tidak menuntut index yang terurut karena pencariannya berdasar komponen jam.
Syarat index terurut#
Penyaringan rentang pada DatetimeIndex mensyaratkan index yang terurut menaik, dan method sort_index() memulihkan urutan tersebut bila sudah rusak. Pengurutan berdasarkan nilai kolom lain, misalnya sort_values("suhu_c"), merusak urutan waktu index, dan pandas menolak rentang string pada index yang tak terurut dengan KeyError. Blok berikut sengaja mengacak urutan baris, menunjukkan penolakannya, lalu memperbaikinya dengan sort_index.
import pandas as pd
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
acak = df.sort_values("suhu_c")
try:
acak.loc["2026-01-05 07:00":"2026-01-05 08:00", ["ruang", "suhu_c"]]
except KeyError as e:
print(type(e).__name__, ":", e)
rapi = acak.sort_index()
print(rapi.loc["2026-01-05 07:00":"2026-01-05 08:00", ["ruang", "suhu_c"]])KeyError : 'Value based partial slicing on non-monotonic DatetimeIndexes with non-existing keys is not allowed.'
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
2026-01-05 08:00:00 Lab A 24.6Pesan KeyError menegaskan bahwa penyaringan rentang berbasis nilai tidak diizinkan pada DatetimeIndex yang tidak monotonic, yaitu tidak terurut menaik. Setelah sort_index() dijalankan, rentang yang sama menghasilkan lima baris persis seperti pada bagian Penyaringan rentang dengan loc. Kedua method pengurutan ini memiliki tugas yang berbeda, yaitu sort_values mengurutkan baris menurut nilai kolom, sedangkan sort_index mengurutkannya menurut label index.
Kesalahan umum#
Penyaringan string parsial gagal dengan KeyError ketika index belum bertipe datetime, dan pesannya sering disalahartikan sebagai data yang hilang. Bila berkas dibaca tanpa parameter parse_dates, kolom waktu masih bertipe teks, sehingga set_index menghasilkan index teks dan pandas mencari label persis bernama 2026-01-05 yang memang tidak ada. Blok berikut menunjukkan kegagalan itu beserta perbaikannya.
import pandas as pd
df_teks = pd.read_csv("sensor_log.csv").set_index("waktu")
print("dtype index:", df_teks.index.dtype)
try:
df_teks.loc["2026-01-05"]
except KeyError as e:
print(type(e).__name__, ":", e)
df = pd.read_csv("sensor_log.csv", parse_dates=["waktu"]).set_index("waktu")
print("baris untuk satu hari:", len(df.loc["2026-01-05"]))dtype index: str
KeyError : '2026-01-05'
baris untuk satu hari: 68Keluaran menunjukkan dtype index str, lalu KeyError: '2026-01-05' yang menunjuk teks yang dicari, dan akhirnya 68 baris setelah parse_dates diberikan pada saat membaca. Perbaikan lainnya adalah konversi lewat pd.to_datetime sebelum set_index, sebagaimana dibahas pada topik Konversi datetime. Pola yang sehat untuk dipegang adalah memastikan dtype index sebelum memakai string parsial, karena pesan errornya tidak selalu mengarah ke penyebab sebenarnya.
Ringkasan#
set_index("waktu")menjadikan kolom waktu sebagai label baris dan menghasilkan DatetimeIndex yang mendukung penyaringan berbasis waktu.df.loc["awal":"akhir"]mengambil rentang label waktu dengan kedua ujung ikut terambil, berbeda dari slicing list Python.- String parsial seperti
"2026-01-05"dan"2026-01-05 07"mengambil satu hari atau satu jam penuh, danbetween_time("08:00", "09:00")mengambil jendela jam yang berulang tiap hari. - Penyaringan rentang menuntut index terurut, dan string parsial menuntut index bertipe datetime, dengan
sort_index()danparse_datessebagai perbaikannya.
Referensi#
- Indexing and selecting data — pandas User Guide — bab resmi seleksi dengan loc beserta sifat rentangnya.
- Time series / date functionality — pandas User Guide — bab resmi deret waktu yang mencakup DatetimeIndex dan string parsial.
- pandas.DataFrame.between_time — pandas API reference — dokumentasi resmi method between_time beserta parameter jendela jamnya.