Olah Data Kode Wilayah Python: Dari Counter Sampai pandas crosstab

Oke, ceritanya begini. Waktu menulis beberapa artikel soal desa dan kelurahan di ideacak, saya butuh angka-angka seperti "berapa kota yang punya desa" atau "berapa persen desa di Jawa Barat yang namanya diawali Ci". Angka seperti itu tidak saya temukan di berita. Jadi saya olah sendiri data kode wilayah Kemendagri yang isinya 83.762 baris, dan ternyata Python bisa menjawabnya dalam beberapa baris kode.

Kartu istilah DataFrame atau tabel data: struktur data pandas berbentuk tabel dengan baris dan kolom berlabel, yang bisa difilter, dikelompokkan, dan dihitung

TL;DR: Data kode wilayah Kepmendagri 2025 tersedia dalam bentuk Excel di repositori GitHub berlisensi CC BY 4.0. Untuk hitungan sederhana, openpyxl ditambah collections.Counter sudah cukup. Begitu pertanyaannya bertambah, seperti desa vs kelurahan per provinsi atau persentase nama berawalan Ci, pandas jauh lebih ringkas lewat value_counts, crosstab, dan groupby. Kode lengkapnya ada di GitHub.

Kenalan Dulu dengan Datanya

Data yang dipakai adalah rangkuman Kepmendagri Nomor 300.2.2-2138 Tahun 2025 dalam bentuk file Excel, dari repositori KODE-WILAYAH-KEPMENDAGRI-2025 (lisensi CC BY 4.0). Satu baris mewakili satu desa, kelurahan, atau desa adat, dengan sembilan kolom:

  • KODE DESA dan NAMA KELURAHAN/DESA/DESA ADAT
  • KODE KECAMATAN dan NAMA KECAMATAN
  • KODE KABUPATEN dan NAMA KABUPATEN
  • KODE PROVINSI dan NAMA PROVINSI
  • TIPE DESA(KELURAHAN, DESA, DESA ADAT)

Format kodenya mengikuti Permendagri Nomor 58 Tahun 2021, misalnya 32.01.13.1007 untuk Kelurahan Pabuaran di Kecamatan Bojonggede. Arti tiap digitnya saya bahas di artikel arti kode NIK KTP.

Yang Perlu Disiapkan

Kode di artikel ini butuh dua library di luar modul bawaan Python:

  • openpyxl, untuk membaca file Excel .xlsx. Library ini dipakai langsung di cara manual, dan juga dipakai pandas di belakang layar saat pd.read_excel() membuka file .xlsx.
  • pandas, untuk mengolah data dalam bentuk tabel (DataFrame).

Saya menguji kodenya dengan Python 3.14, pandas 2.3.3, dan openpyxl 3.1.5. Cara paling gampang memasangnya:

pip install pandas openpyxl

Atau kalau sudah meng-clone repositori kode artikel ini, pakai requirements.txt yang ada di foldernya:

pip install -r requirements.txt

File Excel-nya tidak saya ikutkan di repositori kode artikel ini. Unduh dulu dari repositori aslinya:

curl -L -o KODE-WILAYAH-KEPMENDAGRI-2025.xlsx https://raw.githubusercontent.com/yonatanyl/KODE-WILAYAH-KEPMENDAGRI-2025/main/KODE-WILAYAH-KEPMENDAGRI-2025.xlsx

Cara Manual: openpyxl dan Counter

Pertanyaan pertama paling sederhana: ada berapa desa, kelurahan, dan desa adat? Untuk ini kita belum butuh library besar. Cukup baca Excel baris per baris dengan openpyxl, lalu hitung pakai Counter:

from collections import Counter
from pathlib import Path

from openpyxl import load_workbook

FILE = Path(__file__).with_name("KODE-WILAYAH-KEPMENDAGRI-2025.xlsx")

ws = load_workbook(FILE, read_only=True)["Sheet1"]
jumlah = Counter()
for baris in ws.iter_rows(min_row=2, values_only=True):
    tipe = baris[8]  # kolom "TIPE DESA(KELURAHAN, DESA, DESA ADAT)"
    jumlah[tipe] += 1

for tipe, n in jumlah.most_common():
    print(f"{tipe:<10} {n:>7,}".replace(",", "."))

Hasilnya:

DESA        75.252
KELURAHAN    8.496
DESA ADAT       14

read_only=True penting di sini, karena openpyxl jadi membaca file secara bertahap dan tidak memuat seluruh workbook ke memori. Buat yang terbiasa dengan Java, Counter ini mirip HashMap<String, Integer> yang dipakai dengan merge(key, 1, Integer::sum), bedanya di Python sudah tersedia siap pakai.

Masalahnya muncul saat pertanyaan bertambah. Mau dipecah per provinsi? Perlu Counter bersarang. Mau persentase? Perlu hitung total sendiri. Kodenya cepat membengkak, padahal yang kita mau cuma "tabel ringkasan".

Pakai pandas: Satu Pertanyaan, Satu Baris

Kebutuhan "ringkas data tabel jadi tabel lain" ini persis yang dikerjakan pandas. Datanya dimuat sekali jadi DataFrame, lalu tiap pertanyaan cukup dijawab satu atau dua baris:

from pathlib import Path

import pandas as pd

FILE = Path(__file__).with_name("KODE-WILAYAH-KEPMENDAGRI-2025.xlsx")

df = pd.read_excel(FILE, dtype=str)
df.columns = ["kode", "nama", "kode_kec", "kecamatan", "kode_kab", "kabupaten_kota",
              "kode_prov", "provinsi", "tipe"]

dtype=str sengaja dipakai supaya kode seperti 32.01 tidak berubah jadi angka desimal. Kode wilayah itu label, bukan bilangan.

Jumlah per Jenis dengan value_counts

print(df["tipe"].value_counts())

Hasilnya sama dengan cara manual tadi: 75.252 desa, 8.496 kelurahan, dan 14 desa adat. Bedanya cuma satu baris.

Desa vs Kelurahan per Provinsi dengan crosstab

per_prov = pd.crosstab(df["provinsi"], df["tipe"])
print(per_prov.sort_values("KELURAHAN", ascending=False).head(5))
tipe              DESA  DESA ADAT  KELURAHAN
provinsi
Sulawesi Selatan  2266          0        793
Jawa Timur        7721          0        773
Jawa Tengah       7810          0        753
Sumatera Utara    5417          0        693
Jawa Barat        5311          0        646

crosstab membuat tabel silang: baris provinsi, kolom jenis, isinya jumlah. Ternyata provinsi dengan kelurahan terbanyak adalah Sulawesi Selatan, bukan provinsi di Jawa.

Kabupaten atau Kota dari Kodenya

Menurut Pasal 6 Permendagri 58/2021, kode kabupaten memakai 01 sampai 69 dan kota 71 sampai 99. Aturan ini bisa langsung diterjemahkan jadi kolom baru:

df["jenis_daerah"] = df["kode_kab"].str[-2:].astype(int).map(lambda n: "kota" if n >= 71 else "kabupaten")
print(df.drop_duplicates("kode_kab")["jenis_daerah"].value_counts())

Hasilnya 416 kabupaten dan 98 kota. Catatan kecil: angka ini ikut menghitung satu kabupaten administrasi dan lima kota administrasi di Jakarta, karena keduanya juga punya kode sendiri walaupun bukan daerah otonom.

Dari kolom yang sama, kita bisa mencari kota yang ternyata punya desa:

kota_desa = df[(df["jenis_daerah"] == "kota") & (df["tipe"] != "KELURAHAN")]
print(kota_desa["kabupaten_kota"].value_counts().head(5))
Kota Gunungsitoli    98
Kota Banda Aceh      90
Kota Subulussalam    82
Kota Lhokseumawe     68
Kota Langsa          66

Temuan ini yang saya pakai di artikel beda kabupaten dan kota.

Persentase Nama Berawalan Ci dengan groupby

df["awalan_ci"] = df["nama"].str.lower().str.startswith("ci")
persen_ci = (df.groupby("provinsi")["awalan_ci"].mean() * 100).round(1)
print(persen_ci.sort_values(ascending=False).head(5))
Jawa Barat                       18.0
Banten                           14.6
Daerah Khusus Ibukota Jakarta     8.6
Jawa Tengah                       1.0
Sulawesi Selatan                  0.6

Triknya ada di .mean() pada kolom boolean. True dihitung 1 dan False dihitung 0, jadi rata-ratanya sama dengan proporsi. Angka ini jadi bahan artikel nama tempat berawalan Ci.

Melihat Contoh Nama Berawalan Ci

Persentase saja kurang terasa kalau tidak lihat nama-namanya. Kolom awalan_ci tadi bisa langsung dipakai sebagai filter, lalu dipersempit ke satu kabupaten:

ci = df[df["awalan_ci"]]
contoh = ci[ci["kabupaten_kota"] == "Kabupaten Bogor"]
print(contoh[["kode", "nama", "kecamatan"]].head(10).to_string(index=False))
         kode          nama   kecamatan
32.01.01.1006      Cibinong    Cibinong
32.01.01.1010       Ciriung    Cibinong
32.01.01.1011     Cirimekar    Cibinong
32.01.02.2003     Ciangsana Gunungputri
32.01.02.2007       Cicadas Gunungputri
32.01.02.2008   Cikeas Udik Gunungputri
32.01.03.2002     Citeureup   Citeureup
32.01.04.2002 Cilebut Timur    Sukaraja
32.01.04.2003 Cilebut Barat    Sukaraja
32.01.04.2004       Cibanon    Sukaraja

Di Kabupaten Bogor saja ada 106 desa dan kelurahan yang namanya diawali Ci. Lalu nama apa yang paling sering dipakai di seluruh Indonesia? Cukup value_counts() di kolom nama:

print(ci["nama"].value_counts().head(10))
nama
Cibodas        18
Cibadak        14
Ciherang       13
Cikadu         12
Cibeureum      11
Cisarua        11
Cimanggu       10
Cilangkap      10
Cinta Damai     9
Cicadas         9
Name: count, dtype: int64

Perhatikan baris "Cinta Damai". Nama itu jelas bukan berasal dari cai (air), tapi ikut terhitung karena kebetulan diawali huruf "ci". Ini kelemahan filter startswith("ci"): cepat dan sederhana, tapi tidak paham makna kata. Untuk hitungan kasar per provinsi, efeknya kecil. Tapi kalau butuh angka yang lebih presisi, daftar seperti ini perlu dicek manual atau difilter lebih ketat, misalnya dengan membuang nama yang diawali "cinta".

Kapan Pakai yang Mana?

Dari dua pendekatan ini, aturan praktisnya begini. Kalau cuma butuh satu hitungan dan tidak mau menambah dependency besar, openpyxl dan Counter sudah cukup. Begitu pertanyaannya mulai berbentuk "per kelompok", "persentase", atau "tabel silang", pindah ke pandas.

Satu hal yang perlu diingat: pandas memuat seluruh data ke memori. Untuk 83 ribu baris ini tidak masalah, tapi kalau datanya jutaan baris, pendekatan baris per baris seperti openpyxl read_only bisa lebih hemat.

Jadi, Pertanyaan Apa yang Mau Kamu Jawab?

Buat saya, latihan ini mengubah cara melihat data pemerintah. File Excel puluhan ribu baris yang awalnya kelihatan membosankan ternyata menyimpan banyak cerita, asal pertanyaannya tepat.

Coba modifikasi kodenya untuk daerahmu. Misalnya, ubah filter provinsi ke provinsimu, lalu cari kecamatan dengan desa terbanyak memakai df.groupby("kecamatan").size(). Atau cari nama desa yang paling sering dipakai di seluruh Indonesia dengan df["nama"].value_counts(). Kalau menemukan hasil menarik, ceritakan di kolom komentar.

Source code lengkap artikel ini bisa dilihat di GitHub: olah-data-kode-wilayah

FAQ

Di mana bisa mendapatkan data kode wilayah Kemendagri dalam format Excel? Data kode wilayah Kepmendagri Nomor 300.2.2-2138 Tahun 2025 tersedia dalam format Excel di repositori GitHub KODE-WILAYAH-KEPMENDAGRI-2025 milik yonatanyl, dengan lisensi CC BY 4.0. Setiap baris berisi satu desa, kelurahan, atau desa adat beserta kode dan nama kecamatan, kabupaten/kota, dan provinsinya.

Bagaimana cara membaca file Excel besar di Python tanpa pandas? Gunakan openpyxl dengan load_workbook(file, read_only=True), lalu baca baris demi baris lewat iter_rows(values_only=True). Mode read_only membuat file dibaca bertahap sehingga lebih hemat memori.

Apa fungsi pandas crosstab? pandas.crosstab membuat tabel silang dari dua kolom. Misalnya pd.crosstab(df["provinsi"], df["tipe"]) menghasilkan tabel dengan baris provinsi dan kolom jenis wilayah, berisi jumlah desa, kelurahan, dan desa adat di tiap provinsi.

Kenapa kode wilayah dibaca sebagai teks, bukan angka? Kode wilayah seperti 32.01 adalah label, bukan bilangan. Kalau dibaca sebagai angka, kode itu bisa berubah jadi desimal 32.1 dan kehilangan nol di belakang. Karena itu read_excel dipanggil dengan dtype=str.

Bagaimana menghitung persentase dengan groupby di pandas? Buat kolom boolean dulu, misalnya apakah nama diawali "Ci", lalu panggil groupby("provinsi")["kolom"].mean(). Karena True dihitung 1 dan False dihitung 0, rata-ratanya sama dengan proporsi, tinggal dikali 100 untuk persen.

Referensi

Posting Komentar untuk "Olah Data Kode Wilayah Python: Dari Counter Sampai pandas crosstab"