Data deret waktu jarang terekam pada momen yang sama persis: transaksi kartu masuk pukul 08:05, sedangkan tabel kurs hanya terekam pukul 08:00 dan 10:00. pd.merge() biasa tidak dapat membantu karena kuncinya tidak pernah identik, sehingga hasil gabungan kehilangan baris. pd.merge_asof() menyelesaikan masalah ini dengan mencari pasangan waktu terdekat sesuai arah yang kita tentukan, lengkap dengan batas jarak melalui parameter tolerance. Pada Chapter ini kita menggabungkan transaksi dengan kurs pada tanggal beku 15 Januari 2026, membandingkan tiga pilihan direction, dan mengelompokkan pencarian per gudang dengan by.
Menggabungkan Berdasarkan Kunci Waktu Terdekat #
pd.merge_asof(kiri, kanan, on="waktu") mengambil setiap baris tabel kiri lalu mencari satu baris tabel kanan yang kuncinya terdekat. Berbeda dengan merge biasa yang menuntut kecocokan persis, pencarian asof mengikuti arah waktu: ke belakang (nilai terakhir yang sudah lewat), ke depan (nilai berikutnya yang akan datang), atau ke yang paling dekat. File berikut memakai datetime yang dibuat pd.to_datetime() dengan tanggal beku 2026 agar hasilnya dapat direproduksi.
import pandas as pd
transaksi = pd.DataFrame({
"waktu": pd.to_datetime([
"2026-01-15 08:05", "2026-01-15 09:30", "2026-01-15 11:00",
]),
"nominal_usd": [100, 80, 140],
})
kurs = pd.DataFrame({
"waktu": pd.to_datetime(["2026-01-15 08:00", "2026-01-15 10:00"]),
"rate": [15850.0, 15900.0],
})
# direction="backward": ambil nilai kurs terakhir pada/sebelum waktu transaksi
hasil = pd.merge_asof(transaksi, kurs, on="waktu")
print(hasil)
print()
# Bandingkan tiga pilihan direction pada data yang sama
fwd = pd.merge_asof(transaksi, kurs, on="waktu", direction="forward")
nearest = pd.merge_asof(transaksi, kurs, on="waktu", direction="nearest")
print(fwd["rate"].to_list())
print(nearest["rate"].to_list())
print()
# tolerance: pasangan yang lebih jauh dari 30 menit tidak digabung
toleran = pd.merge_asof(transaksi, kurs, on="waktu", direction="nearest",
tolerance=pd.Timedelta("30min"))
print(toleran)
print()
# by= memisahkan pencarian per kelompok
sensor = pd.DataFrame({
"waktu": pd.to_datetime([
"2026-01-15 08:05", "2026-01-15 08:20", "2026-01-15 09:30",
]),
"gudang": ["A", "B", "A"],
"suhu": [24.5, 26.1, 25.0],
})
pemeliharaan = pd.DataFrame({
"waktu": pd.to_datetime(["2026-01-15 08:00", "2026-01-15 09:00"]),
"gudang": ["A", "A"],
"teknisi": ["Budi", "Siti"],
})
print(pd.merge_asof(sensor, pemeliharaan, on="waktu", by="gudang"))
print()
# merge_asof juga bekerja di atas datetime index
tr = transaksi.set_index("waktu")
kr = kurs.set_index("waktu")
print(pd.merge_asof(tr, kr, left_index=True, right_index=True))Output yang Dihasilkan:
waktu nominal_usd rate
0 2026-01-15 08:05:00 100 15850.0
1 2026-01-15 09:30:00 80 15850.0
2 2026-01-15 11:00:00 140 15900.0
[15900.0, 15900.0, nan]
[15850.0, 15900.0, 15900.0]
waktu nominal_usd rate
0 2026-01-15 08:05:00 100 15850.0
1 2026-01-15 09:30:00 80 15900.0
2 2026-01-15 11:00:00 140 NaN
waktu gudang suhu teknisi
0 2026-01-15 08:05:00 A 24.5 Budi
1 2026-01-15 08:20:00 B 26.1 NaN
2 2026-01-15 09:30:00 A 25.0 Siti
nominal_usd rate
waktu
2026-01-15 08:05:00 100 15850.0
2026-01-15 09:30:00 80 15850.0
2026-01-15 11:00:00 140 15900.0Mari kita telaah bagian-bagian pentingnya:
- Baris 3-13: kolom
waktubertipedatetime64[us], resolusi bawaan pandas 3.0 saatpd.to_datetime()memproses string tanggal. - Baris 15-17 (
directiondefault): tanpa argumendirection, pandas memakai"backward"; transaksi 08:05 dan 09:30 sama-sama memakai kurs 08:00 (15850.0), lalu transaksi 11:00 naik ke kurs 10:00 (15900.0). - Baris 20-24:
direction="forward"mengambil kurs berikutnya sehingga 08:05 memakai nilai 10:00 (15900.0) dan 11:00 tidak punya pasangan (nan);direction="nearest"memilih jarak terpendek, dan transaksi 09:30 yang berjarak tepat 30 menit dari 10:00 jatuh ke 15900.0. - Baris 27-30 (
tolerance): pasangan hanya dibentuk bila jarak waktunya paling lama 30 menit; transaksi 11:00 berjarak 60 menit dari kurs terakhir sehinggaratemenjadiNaN, sinyal untuk ditinjau ulang. - Baris 33-46 (
by=): sensor gudang B tidak mewarisi teknisi gudang A; pencarian asof dijalankan di dalam masing-masing kelompokgudang. - Baris 49-52: bila kedua tabel sudah memakai datetime index, parameter
ondigantileft_index=Truedanright_index=True.
direction: backward, forward, nearest #
Pilihan direction menentukan makna bisnis hasil gabungan. "backward" paling umum untuk konteks “harga yang berlaku saat itu”, seperti kurs yang dicatat sebelum transaksi terjadi. "forward" cocok untuk jadwal: pelatihan berikutnya setiap pegawai, atau pengiriman yang baru akan berangkat. "nearest" berguna ketika dua tabel saling mendekati, misalnya perbandingan dua alat ukur yang tidak pernah menyala bersamaan. Ketiganya menerima tolerance dalam bentuk pd.Timedelta untuk kunci datetime atau bilangan biasa untuk kunci numerik, sehingga pasangan yang terlalu jauh otomatis menjadi NaN.
Kelompok dengan by= dan Index Waktu #
Parameter by menjaga agar pencarian tidak melompat antar kelompok; wajib dipakai saat tabel berisi lebih dari satu lokasi, cabang, atau perangkat. Variannya, left_by dan right_by, mengelompokkan hanya satu sisi bila label kelompok berbeda nama di kedua tabel. Ketika data sudah tersusun sebagai deret waktu ber-index, pola left_index=True, right_index=True menghindari set_index() ganda dan menghasilkan Series atau DataFrame dengan index waktu yang utuh.
Halaman user guide merging
memuat bagian khusus asof merge, dokumentasi pandas.merge_asof
merinci seluruh parameter, dan user guide time series
melengkapi teknik pengolahan kunci waktu. Setelah penggabungan horizontal tuntas, satu anggota keluarga merge tersisa: merge_ordered() untuk union terurut waktu beserta anti-join baru pandas 3.0, dibahas pada Chapter berikutnya sebelum kita beralih ke pivot().