Akses pada dua chapter sebelumnya selalu berupa satu label atau satu tuple kunci. Analisis nyata menuntut kombinasi yang lebih kaya: “semua kategori untuk Jakarta”, “kota Bandung sampai Jakarta”, atau “dua kota tertentu pada bulan 1”. pandas mendukung semua pola itu lewat tuple yang berisi slice(None), list label, atau irisan rentang — dan menyediakan IndexSlice agar penulisannya tetap ringkas. Chapter ini merangkai pola-pola tersebut pada dataset penjualan 27 baris yang sama, termasuk pemakaian IndexSlice pada axis kolom dan satu jebakan urutan index yang sering menghentikan kode pemula.
Irisan Level di Dalam Tuple #
Blok pertama dan kedua script memilih baris Elektronik milik Jakarta pada semua bulan. Kuncinya adalah slice(None), yaitu objek irisan kosong yang berarti “semua isi level ini”.
import pandas as pd
kota_list = ["Jakarta", "Bandung", "Surabaya"]
bulan_list = [1, 2, 3]
kategori_list = ["Elektronik", "Pakaian", "Makanan"]
dasar = {"Elektronik": 420, "Pakaian": 260, "Makanan": 150}
baris = []
for kota in kota_list:
for bulan in bulan_list:
for kategori in kategori_list:
omzet = dasar[kategori] + 30 * kota_list.index(kota) + 12 * (bulan - 1)
baris.append((kota, bulan, kategori, omzet))
penjualan = pd.DataFrame(baris, columns=["kota", "bulan", "kategori", "omzet"])
multi = penjualan.set_index(["kota", "bulan", "kategori"]).sort_index()
idx = pd.IndexSlice
# slice(None) memilih seluruh isi satu level di dalam tuple
print(multi.loc[("Jakarta", slice(None), "Elektronik")])
print()
# IndexSlice memberi penulisan yang setara dan lebih mudah dibaca
print(multi.loc[idx["Jakarta", :, "Elektronik"], :])
print()
# irisan rentang label pada level terluar (index wajib terurut)
print(multi.loc[idx["Bandung":"Jakarta", :, :], :].head(6))
print()
# list label pada satu level, kunci tetap di level lain
print(multi.loc[idx[["Jakarta", "Surabaya"], 1, :], :])
print()
# mask boolean yang dibangun dari nilai satu level
mask = multi.index.get_level_values("bulan") == 3
print(multi.loc[mask].head(4))
print()
# IndexSlice juga bekerja pada axis kolom ber-MultiIndex
kolom = pd.MultiIndex.from_product([["omzet", "unit"], [2025, 2026]])
dfk = pd.DataFrame(
[[320, 300, 12, 11], [210, 240, 8, 9], [150, 170, 6, 7]],
index=["Jan", "Feb", "Mar"],
columns=kolom,
)
print(dfk.loc[:, idx[:, 2026]])
print()
# irisan pada index yang belum terurut memunculkan UnsortedIndexError
kacau = penjualan.set_index(["kota", "bulan", "kategori"])
try:
kacau.loc[idx["Bandung":"Jakarta", :, :], :]
except pd.errors.UnsortedIndexError as e:
print("UnsortedIndexError:", str(e))Output yang Dihasilkan:
omzet
bulan
1 420
2 432
3 444
omzet
kota bulan kategori
Jakarta 1 Elektronik 420
2 Elektronik 432
3 Elektronik 444
omzet
kota bulan kategori
Bandung 1 Elektronik 450
Makanan 180
Pakaian 290
2 Elektronik 462
Makanan 192
Pakaian 302
omzet
kota bulan kategori
Jakarta 1 Elektronik 420
Makanan 150
Pakaian 260
Surabaya 1 Elektronik 480
Makanan 210
Pakaian 320
omzet
kota bulan kategori
Bandung 3 Elektronik 474
Makanan 204
Pakaian 314
Jakarta 3 Elektronik 444
omzet unit
2026 2026
Jan 300 11
Feb 240 9
Mar 170 7
UnsortedIndexError: 'MultiIndex slicing requires the index to be lexsorted: slicing on levels [0], lexsort depth 0'Mari kita bedah bagian pentingnya:
- Baris 20 (
("Jakarta", slice(None), "Elektronik")): tuple tiga elemen denganslice(None)di tengah menghasilkan tiga baris omzet Elektronik Jakarta (420,432,444) dan menyisakan levelbulansebagai index hasil. - Baris 24 (
idx["Jakarta", :, "Elektronik"]):idx = pd.IndexSlicepada baris 17 membuat penulisan yang setara tetapi lebih ringkas; tanda:di sini adalah sintaks Python untukslice(None). - Baris 28 (rentang
"Bandung":"Jakarta"): irisan label pada level terluar menghasilkan 18 baris dua kota; output menampilkan enam baris pertamanya dengan label Bandung dan Jakarta berdampingan. - Baris 32 (list dua kota):
["Jakarta", "Surabaya"]memilih dua kota sekaligus pada bulan 1, menghasilkan enam baris yang urutannya mengikuti urutan list.
Syarat Mutlak: Index Harus Terurut #
Irisan rentang hanya boleh dijalankan pada MultiIndex yang sudah terurut leksikografis. Blok terakhir script sengaja menyerahkan DataFrame tanpa sort_index() dan menangkap galatnya: pandas melempar UnsortedIndexError dengan pesan MultiIndex slicing requires the index to be lexsorted. Akses parsial seperti multi.loc["Jakarta"] masih aman pada index tak terurut, tetapi begitu kita memakai tanda : rentang pada level mana pun, urutan menjadi syarat wajib. Pola amannya sederhana: panggil sort_index() sekali setelah set_index().
Mask Boolean dari Level Index #
Kondisi berbasis nilai kolom sudah kita kuasai lewat boolean masking; untuk MultiIndex, kondisi dibangun dari get_level_values("bulan"). Baris 36 membuat mask True untuk sembilan baris bulan 3, lalu baris 37 menerapkannya lewat .loc[mask]. Pola ini melengkapi IndexSlice: slice memilih berdasarkan posisi label, sedangkan mask memilih berdasarkan kondisi yang kita tulis sendiri, misalnya omzet > 440.
IndexSlice pada Axis Kolom #
MultiIndex tidak hanya hidup di baris. Baris 41-47 membuat DataFrame dengan kolom bertingkat omzet/unit × 2025/2026, lalu baris 47 memakai dfk.loc[:, idx[:, 2026]]; perhatikan penulisan idx[:, 2026]: level pertama (nama metrik) dibiarkan terbuka, level kedua (tahun) disaring. Hasilnya dua kolom tahun 2026 dengan nilai omzet 300, 240, 170. Sintaks yang sama bekerja untuk kedua axis sekaligus bila perlu, sehingga tabel hasil pivot berukuran besar tetap mudah dipotong.
Seleksi bertingkat kini lengkap: label tunggal, tuple, irisan, list, mask, dan kolom bertingkat. Langkah berikutnya kembali ke komputasi: fungsi agregasi buatan sendiri yang dipasang pada groupby().agg(), termasuk kontrak yang wajib dipenuhi agar fungsi kita diterima pandas.
Referensi resmi untuk chapter ini: user guide MultiIndex / Advanced Indexing , pandas.IndexSlice , dan user guide Indexing and selecting data .