Merge adalah operasi pandas yang paling sering menghasilkan “data benar tapi salah jumlah”. Empat pelanggan digabungkan dengan lima pesanan bisa menghasilkan enam baris, dan pandas tidak menganggap itu kesalahan — hasil itu memang definisi dari join yang diminta. Chapter ini memberi kita alat pemeriksaan yang sistematis: membandingkan jumlah baris sebelum dan sesudah merge, menemukan kunci join yang duplikat, memetakan asal setiap baris dengan indicator=True, dan mengeksekusi bentuk relasi dengan validate=.
Kenapa Jumlah Baris Bisa Berubah #
Aturan dasarnya sederhana: satu baris kiri dipasangkan dengan setiap baris kanan yang kuncinya sama. Jika satu pelanggan punya tiga pesanan, hasil merge memuat tiga baris untuk pelanggan tersebut. Perilaku ini benar menurut definisi join, tetapi jarang menjadi keinginan saat kita hanya ingin membawa atribut tambahan. Karena itu pemeriksaan pertama saat hasil merge tidak sesuai ekspektasi selalu berupa perbandingan angka sederhana, bukan pembacaan kode ulang. Script berikut memakai data pelanggan dan pesanan Toko Maju Jaya untuk mendemokan semua alat pemeriksaannya.
import pandas as pd
pelanggan = pd.DataFrame(
{
"id_pelanggan": [1, 2, 3, 4],
"nama": ["Budi", "Siti", "Dewi", "Rian"],
}
)
pesanan = pd.DataFrame(
{
"id_pelanggan": [1, 1, 2, 2, 9],
"kode": ["TRX-001", "TRX-002", "TRX-003", "TRX-004", "TRX-005"],
"total": [50_000, 30_000, 20_000, 45_000, 25_000],
}
)
print("--- jumlah baris sebelum dan sesudah merge ---")
print("baris pelanggan :", len(pelanggan))
print("baris pesanan :", len(pesanan))
gabungan = pelanggan.merge(pesanan, on="id_pelanggan", how="left")
print("baris hasil :", len(gabungan))
print()
print("--- deteksi kunci duplikat di kedua sisi ---")
print("pesanan per id:", pesanan["id_pelanggan"].value_counts().sort_index().to_dict())
print("pelanggan unik:", pelanggan["id_pelanggan"].is_unique)
print()
print("--- indicator=True memetakan asal baris ---")
laporan = pelanggan.merge(pesanan, on="id_pelanggan", how="outer", indicator=True)
print("kategori _merge :", laporan["_merge"].value_counts().to_dict())
print("left_only :", laporan.loc[laporan["_merge"] == "left_only", "nama"].tolist())
print("right_only :", laporan.loc[laporan["_merge"] == "right_only", "kode"].tolist())
print()
print("--- validate= menjaga bentuk relasi ---")
aman = pesanan.merge(pelanggan, on="id_pelanggan", validate="many_to_one")
print("many_to_one -> ok, baris:", len(aman))
try:
pelanggan.merge(pesanan, on="id_pelanggan", validate="one_to_one")
except pd.errors.MergeError as exc:
print("one_to_one ->", type(exc).__name__)
print("pesan :", str(exc).splitlines()[0])
print()
print("--- kolom sama-sama bernama stok ---")
stok_kasir = pd.DataFrame({"kode_barang": ["B01"], "stok": [10]})
stok_gudang = pd.DataFrame({"kode_barang": ["B01"], "stok": [99]})
gabung = stok_kasir.merge(stok_gudang, on="kode_barang")
print("suffix default:", gabung.columns.tolist())
try:
stok_kasir.merge(stok_gudang, on="kode_barang", suffixes=("", ""))
except ValueError as exc:
print("suffix kosong ->", str(exc))Output yang Dihasilkan:
--- jumlah baris sebelum dan sesudah merge ---
baris pelanggan : 4
baris pesanan : 5
baris hasil : 6
--- deteksi kunci duplikat di kedua sisi ---
pesanan per id: {1: 2, 2: 2, 9: 1}
pelanggan unik: True
--- indicator=True memetakan asal baris ---
kategori _merge : {'both': 4, 'left_only': 2, 'right_only': 1}
left_only : ['Dewi', 'Rian']
right_only : ['TRX-005']
--- validate= menjaga bentuk relasi ---
many_to_one -> ok, baris: 4
one_to_one -> MergeError
pesan : Merge keys are not unique in right dataset; not a one-to-one merge
--- kolom sama-sama bernama stok ---
suffix default: ['kode_barang', 'stok_x', 'stok_y']
suffix kosong -> columns overlap but no suffix specified: Index(['stok'], dtype='str')Mari kita bedah bagian pentingnya:
- Perbandingan
len()tiga arah:pelangganpunya 4 baris,pesanan5 baris, hasil merge 6 baris. Selisihlen(gabungan) - len(pelanggan) = 2langsung memberi tanda bahwa dua pelanggan muncul lebih dari satu kali di sisi pesanan. Angka ini sebaiknya dihitung setiap kali kita menulis merge baru. value_counts()pada kunci: pesanan per id adalah{1: 2, 2: 2, 9: 1}, jadi kunci1dan2duplikat di sisi kanan. Di sisi lainpelanggan["id_pelanggan"].is_uniquebernilaiTrue. Kombinasi “kiri unik, kanan duplikat” menjelaskan dari mana dua baris tambahan berasal.indicator=True: kolom_mergemengelompokkan setiap baris hasil outer join menjadiboth,left_only, atauright_only. Hasilnya{'both': 4, 'left_only': 2, 'right_only': 1}— pelanggan Dewi dan Rian tidak punya pesanan, sedangkan pesananTRX-005(id 9) tidak punya pelanggan. Kunci id 9 seperti ini biasanya berasal dari data uji yang tertinggal dan layak diperiksa ke sumbernya.validate="many_to_one": relasi “banyak pesanan per satu pelanggan” cocok dengan data, sehingga merge diterima. Kalau struktur data berubah suatu hari (misalnya pelanggan ikut duplikat), merge yang sama akan langsung ditolak — masalah terdeteksi di baris merge, bukan saat laporan sudah jadi.validate="one_to_one": munculpd.errors.MergeErrordengan pesan pertamaMerge keys are not unique in right dataset; not a one-to-one merge. Pesan ini menyebut sisi mana yang duplikat, sehingga pemeriksaan kunci langsung terarah.- Kolom dengan nama sama: dua DataFrame yang sama-sama punya kolom
stokotomatis diberi suffixstok_xdanstok_y. Suffix bawaan seperti ini mudah luput dibaca. Memberisuffixes=("", "")memicu errorcolumns overlap but no suffix specified— pola yang praktis untuk memastikan kita tidak pernah memakai_x/_ytanpa sadar; sebutkan suffix yang bermakna, misalnyasuffixes=("_kasir", "_gudang").
Alat Pemeriksaan Merge Sekali Pandang #
| Alat | Kegunaan |
|---|---|
len() sebelum vs sesudah | Mendeteksi penggandaan baris atau baris yang tidak ikut |
value_counts() pada kunci | Menemukan kunci duplikat di tiap sisi |
is_unique | Menegaskan apakah kunci layak jadi satu-satu |
indicator=True | Memetakan baris ke both / left_only / right_only |
validate= | Menolak merge yang bentuk relasinya berubah |
suffixes= | Menamai kolom yang bentrok dengan bermakna |
Begitu jumlah baris terkendali, sumber keanehan berikutnya sering berada di tipe data: kunci join yang tampak sama tapi dtype-nya berbeda, atau kolom angka yang berubah bentuk saat dibaca. Topik itu kita bahas tuntas pada chapter Debugging dtype.
Referensi resmi untuk chapter ini: Merge, join, concatenate and compare , pandas.DataFrame.merge , dan pandas.errors.MergeError .