Pembacaan data time-series didominasi oleh tiga pola, yaitu pemindaian rentang waktu, last-known-value per deret, dan agregasi atas jendela waktu. Topik ini membedah ketiga pola tersebut dengan ilustrasi pandas pada dataset telemetri satu hari penuh, lalu menunjukkan bagaimana masing-masing memetakan ke operasi indeks dan kompresi di sisi mesin. Setelah membaca topik ini, pilihan indeks dan strategi pemartisian menjadi lebih mudah dijustifikasi berdasarkan pola akses yang nyata.
Pemindaian rentang waktu#
Pola pembacaan yang paling lazim adalah pemindaian rentang, yaitu pengambilan seluruh titik yang cap waktunya berada dalam sebuah interval. Contoh klasiknya adalah “suhu 12 jam terakhir” atau “data metrik antara dua titik waktu”. Karena data time-series terurut menurut cap waktu, pemindaian rentang menjadi operasi yang dapat dilayani oleh satu seek ke indeks waktu, lalu pemindaian berurutan pada rentang tersebut. Jika tabel dipartisi menurut waktu, hanya satu atau beberapa partisi yang perlu disentuh, sehingga biaya tidak bergantung pada ukuran tabel penuh.
Pada pandas, operasi ini dinyatakan dengan df.loc[awal:akhir] setelah kolom ts dijadikan indeks. Pada SQL, padanannya adalah WHERE ts BETWEEN awal AND akhir. Kedua bentuk ini secara semantik setara, dan keduanya memanfaatkan keterurutan untuk memangkas rentang sebelum pemindaian baris benar-benar terjadi. Pola ini sangat berbeda dari query operasional yang memilih satu baris berdasarkan kunci primer, sebab di sini rentang, bukan titik, yang menjadi target.
Last-known-value per deret#
Pola kedua adalah pengambilan nilai terakhir yang diketahui untuk setiap deret. Pada dashboard pemantauan, pola ini menjadi tulang punggung tampilan status terkini, yaitu “suhu terakhir sensor A”, “beban CPU terakhir host B”, dan sebagainya. Operasi ini secara konseptual adalah agregasi MAX(ts) per deret, lalu penggabungan kembali untuk mengambil nilai pada cap waktu maksimum tersebut. Pada sistem dengan banyak deret, biaya pola ini bergantung pada ketersediaan indeks (sensor_id, ts DESC) yang memungkinkan pengambilan nilai terakhir tanpa memindai seluruh deret.
Pada pandas, padanannya adalah df.groupby("sensor_id").tail(1), yaitu pengelompokan berdasarkan identitas deret lalu pengambilan baris terakhir dari setiap kelompok. Operasi ini mengasumsikan bahwa baris terakhir dalam pengelompokan adalah baris dengan cap waktu terbesar. Asumsi itu valid hanya bila pengelompokan menghormati urutan kronologi, sehingga sebelum groupby biasanya perlu dilakukan sort_values("ts"). Tanpa pengurutan, baris “terakhir” hanyalah baris yang kebetulan berada di ujung, bukan baris dengan cap waktu terbesar.
Agregasi atas jendela waktu#
Pola ketiga adalah agregasi atas jendela waktu, yaitu pemangkasan data mentah menjadi ringkasan per interval. Contoh klasiknya adalah “rerata suhu per 15 menit” atau “jumlah titik per jam”. Pola ini menjadi inti dari hampir setiap dashboard dan alerting, sebab data mentah per detik terlalu padat untuk ditampilkan langsung. Operasi ini disebut bucketing atau windowing, dan pandas menyediakannya melalui resample, sementara SQL menyediakannya melalui fungsi seperti time_bucket pada TimescaleDB atau date_bin pada Postgres 14+.
Agregasi jendela menghasilkan kolom baru yang khas, yaitu min, max, mean, dan count. Pemilihan agregat bergantung pada pertanyaan yang ingin dijawab: mean untuk kecenderungan umum, min/max untuk rentang ekstrem, dan count untuk verifikasi kelengkapan. Jendela yang lebih lebar, misalnya satu jam, menghasilkan rangkaian yang lebih halus tetapi menyembunyikan fluktuasi singkat. Jendela yang lebih sempit, misalnya satu menit, mempertahankan resolusi tetapi tidak mengurangi beban visual. Pilihan jendela adalah keputusan desain, bukan optimasi.
Tiga pola dalam satu dataset#
Skrip Python berikut membangkitkan 1.440 titik telemetri (satu hari penuh, interval satu menit) dengan satu sensor, lalu memperlihatkan ketiga pola dalam satu eksekusi. Pemindaian rentang memotong satu jam pada siang hari, last-known-value mengambil baris termutakhir, dan agregasi jendela menghitung min, max, mean, dan count per 15 menit. Skrip menggunakan pandas untuk keseluruhan operasi, dan pola yang sama dapat dipindahkan ke SQL tanpa perubahan semantik.
"""Demonstrasi pola pembacaan data time-series.
Skrip membangkitkan 1440 titik telemetri (satu hari, interval satu menit),
lalu memperlihatkan tiga pola pembacaan yang lazim pada data time-series,
yaitu pemindaian rentang (range scan), last-known-value per deret, dan
agregasi atas jendela waktu. Tujuannya menunjukkan bahwa pola pembacaan
time-series berbeda dari query operasional biasa.
"""
from __future__ import annotations
from datetime import datetime, timezone
import numpy as np
import pandas as pd
AWAL = datetime(2026, 1, 1, 0, 0, tzinfo=timezone.utc)
JUMLAH_TITIK = 1_440
FREKUENSI = "1min"
def bangun_telemetri() -> pd.DataFrame:
cap_waktu = pd.date_range(AWAL, periods=JUMLAH_TITIK, freq=FREKUENSI, tz="UTC")
rng = np.random.default_rng(42)
suhu = 24.0 + np.sin(np.arange(JUMLAH_TITIK) / 60.0) + rng.normal(0, 0.2, JUMLAH_TITIK)
return pd.DataFrame({
"ts": cap_waktu,
"sensor_id": "sensor-01",
"suhu_c": np.round(suhu, 2),
}).set_index("ts")
def pemindaian_rentang(df: pd.DataFrame) -> pd.DataFrame:
awal = AWAL.replace(hour=12, minute=0, second=0)
akhir = awal + pd.Timedelta(hours=1)
return df.loc[awal:akhir]
def last_known_value(df: pd.DataFrame) -> pd.DataFrame:
return df.groupby("sensor_id").tail(1)
def agregasi_jendela(df: pd.DataFrame) -> pd.DataFrame:
return (
df.resample("15min")["suhu_c"]
.agg(["min", "max", "mean", "count"])
.round(2)
)
def main() -> None:
df = bangun_telemetri()
print("jumlah baris:", len(df))
print("rentang waktu:", df.index.min(), "->", df.index.max())
print()
rentang = pemindaian_rentang(df)
print("pemindaian rentang 12:00-13:00:", len(rentang), "baris")
print(rentang.head(3).to_string())
print("...")
print(rentang.tail(2).to_string())
print()
lk = last_known_value(df)
print("last-known-value per sensor:")
print(lk.to_string())
print()
agg = agregasi_jendela(df)
print("agregasi 15 menit (5 baris pertama):")
print(agg.head(5).to_string())
print()
print("agregasi 15 menit (5 baris terakhir):")
print(agg.tail(5).to_string())
if __name__ == "__main__":
main()jumlah baris: 1440
rentang waktu: 2026-01-01 00:00:00+00:00 -> 2026-01-01 23:59:00+00:00
pemindaian rentang 12:00-13:00: 61 baris
sensor_id suhu_c
ts
2026-01-01 12:00:00+00:00 sensor-01 23.44
2026-01-01 12:01:00+00:00 sensor-01 23.70
2026-01-01 12:02:00+00:00 sensor-01 23.04
...
sensor_id suhu_c
ts
2026-01-01 12:59:00+00:00 sensor-01 24.14
2026-01-01 13:00:00+00:00 sensor-01 24.41
last-known-value per sensor:
sensor_id suhu_c
ts
2026-01-01 23:59:00+00:00 sensor-01 23.31
agregasi 15 menit (5 baris pertama):
min max mean count
ts
2026-01-01 00:00:00+00:00 23.68 24.44 24.12 15
2026-01-01 00:15:00+00:00 24.08 24.60 24.36 15
2026-01-01 00:30:00+00:00 24.36 24.91 24.60 15
2026-01-01 00:45:00+00:00 24.47 25.11 24.78 15
2026-01-01 01:00:00+00:00 24.50 25.08 24.86 15
agregasi 15 menit (5 baris terakhir):
min max mean count
ts
2026-01-01 22:45:00+00:00 22.90 23.55 23.28 15
2026-01-01 23:00:00+00:00 22.57 23.40 23.03 15
2026-01-01 23:15:00+00:00 22.75 23.42 23.06 15
2026-01-01 23:30:00+00:00 22.69 23.45 23.11 15
2026-01-01 23:45:00+00:00 22.48 23.31 22.98 15Keluaran di atas memperlihatkan tiga hal penting. Pertama, pemindaian rentang satu jam menghasilkan 61 baris, yaitu setiap menit dari 12:00 hingga 13:00 inklusif. Kedua, last-known-value mengembalikan satu baris dengan cap waktu 23:59, yang merupakan baris terakhir deret. Ketiga, agregasi 15 menit menghasilkan rangkaian yang jauh lebih padat, yaitu 96 baris dari yang sebelumnya 1.440, dengan setiap baris merangkum min, max, mean, dan count. Angka count yang konstan bernilai 15 menunjukkan tidak ada celah pada deret, sedangkan nilai yang berbeda dari 15 akan menjadi penanda data hilang.
Kesalahan umum#
- Mengambil baris terakhir tanpa mengurutkan menurut cap waktu. Pada data dengan late arrival, baris “terakhir” secara fisik belum tentu memiliki cap waktu terbesar, sehingga last-known-value menjadi salah.
- Memilih resolusi jendela yang terlalu halus untuk dashboard. Resolusi satu menit pada layar 1.080 piksel menghasilkan kepadatan titik yang menenggelamkan pola, sehingga agregasi 15 menit atau satu jam biasanya lebih tepat untuk visualisasi.
- Mengabaikan kolom
countpada agregasi. Tanpacount, tidak ada cara untuk membedakan rerata yang dihitung dari 15 titik dengan rerata yang dihitung dari 3 titik, padahal keduanya memiliki keandalan yang sangat berbeda.
Ringkasan#
- Tiga pola pembacaan khas time-series adalah pemindaian rentang, last-known-value, dan agregasi atas jendela waktu.
- Pemindaian rentang memanfaatkan keterurutan untuk memangkas pencarian ke sebagian kecil tabel.
- last-known-value bergantung pada indeks
(sensor_id, ts DESC)dan pada urutan kronologi yang benar sebelumgroupby. - Agregasi jendela mengubah data mentah per detik menjadi rangkaian per menit atau per jam yang layak ditampilkan, dengan kolom
countsebagai penanda kelengkapan.
Referensi#
- Use time buckets — Tiger Data
— Penjelasan resmi fungsi
time_bucketTimescaleDB untuk agregasi atas jendela waktu dengan berbagai interval. - Resample — pandas
— Dokumentasi resmi operasi
resamplepada pandas sebagai padanantime_bucketdi sisi klien. - Window Functions — PostgreSQL
— Mekanisme
OVERdanPARTITION BYpada Postgres yang menjadi dasar pola pembacaan jendela.