Chapter-chapter sebelumnya membuat setiap langkah kita teruji; chapter penutup ini membuat seluruh rangkaian bisa diulang dengan hasil yang sama. Reproducibilitas adalah syarat dasar debugging yang sehat: jika hasil analisis berubah setiap kali dijalankan, test dan gerbang validasi tidak ada gunanya karena rujukannya sendiri bergerak. Tiga pilar menopangnya — seed untuk angka acak, catatan versi pustaka, dan tanggal serta data uji yang beku. Script pada chapter ini menyatukan ketiganya dalam satu pipeline kecil yang terbukti menghasilkan output identik pada setiap eksekusi.
Menyematkan Seed pada Sumber Acak #
Angka acak muncul di mana-mana pada pekerjaan data: sampling baris, simulasi data uji, inisialisasi parameter. Angka-angka itu tidak perlu dihindari — cukup dibuat terulang. Generator modern NumPy, np.random.default_rng(seed), menghasilkan deret nilai yang sama selama seed-nya sama, dan instansinya diteruskan ke pemanggilan berikutnya sehingga urutannya tetap terjaga. Method sample() milik pandas memiliki padanannya sendiri, yaitu parameter random_state, sehingga baris yang terpilih juga tetap. Kebiasaannya: satu konstanta SEED di bagian atas skrip, dipakai oleh semua sumber acak di bawahnya.
Pipeline Kecil yang Terbukti Dapat Diulang #
Skrip berikut merangkai semuanya: konstanta konfigurasi di atas, generator data transaksi dengan seed, fungsi agregasi, pembuktian dua eksekusi menghasilkan hasil yang equals, sampel dengan random_state, dan uji simpan-baca kembali ke CSV dalam folder sementara yang otomatis dihapus.
import numpy as np
import pandas as pd
from datetime import date
from tempfile import TemporaryDirectory
SEED = 42
TANGGAL_LAPORAN = date(2026, 1, 15)
KOTA = np.array(["Jakarta", "Bandung", "Surabaya", "Medan"])
PRODUK = np.array(["Gula", "Minyak", "Beras", "Kopi"])
def bangun_transaksi(n: int = 8) -> pd.DataFrame:
"""Bangun data transaksi dengan rng berseed — sama di setiap eksekusi."""
rng = np.random.default_rng(SEED)
return pd.DataFrame(
{
"kode_transaksi": [f"TRX-{i:03d}" for i in range(1, n + 1)],
"cabang": rng.choice(KOTA, size=n),
"produk": rng.choice(PRODUK, size=n),
"jumlah": rng.integers(1, 10, size=n),
"harga": rng.choice([15_000, 20_000, 30_000], size=n),
}
)
def rangkum(df: pd.DataFrame) -> pd.DataFrame:
"""Agregasi: total jumlah per cabang, diurutkan menurut nama cabang."""
return (
df.groupby("cabang", as_index=False)["jumlah"]
.sum()
.sort_values("cabang")
.reset_index(drop=True)
)
print("--- konfigurasi yang dicatat ---")
print("pandas :", pd.__version__)
print("numpy :", np.__version__)
print("seed :", SEED)
print("tanggal:", TANGGAL_LAPORAN)
print()
print("--- data transaksi dari rng berseed ---")
print(bangun_transaksi().to_string(index=False))
print()
print("--- pipeline dijalankan dua kali ---")
hasil_1 = rangkum(bangun_transaksi())
hasil_2 = rangkum(bangun_transaksi())
print("hasil_1.equals(hasil_2):", hasil_1.equals(hasil_2))
print(hasil_1.to_string(index=False))
print()
print("--- sampel dengan random_state ---")
sampel = bangun_transaksi().sample(3, random_state=SEED)
print("baris terpilih:", sampel["kode_transaksi"].tolist())
print()
print("--- simpan dan baca kembali ---")
with TemporaryDirectory() as folder:
jalur = f"{folder}/transaksi.csv"
bangun_transaksi().to_csv(jalur, index=False)
baca = pd.read_csv(jalur)
print("roundtrip equals:", bangun_transaksi().equals(baca))Output yang Dihasilkan:
--- konfigurasi yang dicatat ---
pandas : 3.0.6
numpy : 2.1.3
seed : 42
tanggal: 2026-01-15
--- data transaksi dari rng berseed ---
kode_transaksi cabang produk jumlah harga
TRX-001 Jakarta Gula 5 30000
TRX-002 Medan Gula 2 20000
TRX-003 Surabaya Beras 8 20000
TRX-004 Bandung Kopi 5 30000
TRX-005 Bandung Beras 5 20000
TRX-006 Medan Kopi 4 20000
TRX-007 Jakarta Beras 2 20000
TRX-008 Surabaya Kopi 9 15000
--- pipeline dijalankan dua kali ---
hasil_1.equals(hasil_2): True
cabang jumlah
Bandung 10
Jakarta 7
Medan 6
Surabaya 17
--- sampel dengan random_state ---
baris terpilih: ['TRX-002', 'TRX-006', 'TRX-001']
--- simpan dan baca kembali ---
roundtrip equals: TrueMari kita bedah bagian pentingnya:
- Konstanta di atas file:
SEED = 42danTANGGAL_LAPORAN = date(2026, 1, 15)menjadi satu-satunya tempat yang perlu diubah bila skenario berubah. Tanggal laporan ditulis eksplisit — bukandate.today()— sehingga hasil tidak tergantung hari eksekusi. np.random.default_rng(SEED): dibuat di dalambangun_transaksi(), sehingga setiap pemanggilan menghasilkan urutan angka yang sama persis: delapan baris transaksi dengan cabang, produk, jumlah, dan harga yang selalu identik pada output.hasil_1.equals(hasil_2): pipeline dijalankan dua kali dan perbandingannyaTrue. Angka per cabang — Bandung 10, Jakarta 7, Medan 6, Surabaya 17 — kini menjadi pegangan yang sah: menggeser salah satu artinya ada kode atau data yang berubah.sample(3, random_state=SEED): baris terpilih selalu['TRX-002', 'TRX-006', 'TRX-001']. Tanparandom_state, baris yang terpilih berbeda setiap eksekusi dan laporan berbasis sampel sulit diperiksa ulang.- Uji simpan-baca kembali:
to_csv()ke folderTemporaryDirectory()laluread_csv()menghasilkan DataFrame yangequalsdengan asalnya, termasuk dtype-nya. Folder sementara itu dihapus otomatis saat blokwithberakhir, jadi bundle tidak menyimpan artefak. pd.__version__dannp.__version__: versi pustaka dicetak di awal. Ketika seorang kolega mendapatkan angka yang berbeda, perbandingan versi adalah pertanyaan pertama — kombinasi pandas 3.0.6 dengan numpy 2.1.3 adalah lingkungan tempat semua contoh course ini diverifikasi.
Daftar Periksa Reproducibilitas #
| Pilar | Yang dilakukan | Alat |
|---|---|---|
| Acak terulang | Satu SEED untuk semua sumber acak | np.random.default_rng(), random_state= |
| Lingkungan tercatat | Versi pandas/numpy dicatat bersama hasil | pd.__version__, np.__version__ |
| Waktu beku | Tanggal laporan eksplisit, bukan hari ini | date(2026, 1, 15) |
| Data uji tetap | Input kecil di dalam skrip, bukan file eksternal | DataFrame konstruksi + assert_frame_equal() |
| Roundtrip teruji | Simpan-baca kembali menghasilkan objek yang sama | to_csv() + read_csv() + equals() |
Section Pengujian dan Debugging sampai di sini: kita bisa membaca error, melacak index, merge, dan dtype, menguji DataFrame dan transformasinya, memasang gerbang schema, serta mengunci seluruh rangkaian agar dapat direproduksi. Langkah berikutnya adalah menyusun kemampuan itu menjadi struktur yang utuh — section Praktik Data Engineering membuka dengan chapter Membangun Pipeline Data, yang menyusun tahapan extract, transform, dan load menjadi fungsi-fungsi pandas yang terstruktur.
Referensi resmi untuk chapter ini: random sampling NumPy , pandas.DataFrame.sample , dan whatsnew v3.0.0 .