import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import os import csv import os.path import pandas as pd import re import numpy as np import math def kategorikan(amar): if amar is None: return None a = amar.lower().strip() if ("seumur hidup" in a): return "penjara seumur hidup" # 1. Pidana Penjara if ("pidana penjara" in a) or ("kurungan" in a) or ("subsider penjara" in a): return "pidana penjara" # 2. Pidana Denda if ("pidana denda" in a) or ("subsider denda" in a): return "pidana denda" # 3. Hukuman Mati if "pidana mati" in a: return "pidana mati" # 4. Bebas Dakwaan if ("bebas dari dakwaan" in a) or ("lepas dari tuntutan" in a) \ or ("membebaskan" in a and "dakwaan" in a): return "bebas dakwaan" # 5. Bebas Bersyarat if ("pidana bersyarat" in a) or ("restorative justice" in a) \ or ("dikembalikan kepada orang tua" in a) \ or ("pidana tambahan" in a) \ or ("lain-lain" in a) or ("lain lain" in a) or ("lain-lain" in a) \ or ("penghentian pemeriksaan perkara" in a): return "bebas bersyarat" # 6. Terdakwa meninggal → drop (return None) if "meninggal" in a: return None # 7. Tidak dikenali → drop return None # Fungsi ekstraksi lama penjara (bulan) def extract_penjara(text): if pd.isna(text): return None # cari tahun tahun = re.search(r'(\d+)\s*\(.*?\)\s*tahun', text, re.IGNORECASE) tahun = int(tahun.group(1)) if tahun else 0 # cari bulan bulan = re.search(r'(\d+)\s*\(.*?\)\s*bulan', text, re.IGNORECASE) bulan = int(bulan.group(1)) if bulan else 0 return tahun * 12 + bulan # total bulan # Fungsi ekstraksi nilai denda def extract_denda(text): if pd.isna(text): return None # cari angka setelah "pidana denda sebesar rp" match = re.search(r'pidana denda\s*(sebesar|sejumlah|retribusi+\s+sebesar|restribusi+\s+sebesar)?\s*(?:rp\.?\s*){1,2}([\d.]+)', text, re.IGNORECASE) #print(match) if match: # hapus titik sebagai pemisah ribuan, ubah jadi integer return int(match.group(2).replace('.', '')) return None # Fungsi utama untuk apply ke DataFrame def proses_amar(row): cat = row["kategori_bersih"] # kolom kategori utama: pidana_penjara / pidana_denda / dll text = row["catatan_amar"] if cat == "pidana penjara": return extract_penjara(text), None elif cat == "pidana denda": return None, extract_denda(text) else: # kategori lain → kosong return None, None def ringkasan(df): # hitung jumlah kasus per tindak pidana total_kasus = len(df) # fungsi bantu untuk menghitung persentase kategori hukuman def pct_cat(subdf, cat): return round(100 * (subdf['kategori_bersih'] == cat).sum() / len(subdf), 3) # agregasi summary = [] for tp, group in df.groupby('kata_kunci'): rata_penjara = round(group.loc[group['kategori_bersih']=='pidana penjara', 'lama_penjara'].mean(), 1) rata_denda = round(group.loc[group['kategori_bersih']=='pidana denda', 'banyak_denda'].mean(), 0) pct_penjara = pct_cat(group, 'pidana penjara') pct_seumur = pct_cat(group, 'penjara seumur hidup') pct_denda = pct_cat(group, 'pidana denda') pct_bebas_bersyarat = pct_cat(group, 'bebas bersyarat') pct_bebas_dakwaan = pct_cat(group, 'bebas dakwaan') pct_mati = pct_cat(group, 'pidana mati') pct_kasus = round(100 * len(group) / total_kasus, 3) summary.append({ 'tindak pidana': tp, 'rata-rata penjara': rata_penjara, 'rata-rata denda': rata_denda, 'penjara': f"{pct_penjara}", 'penjara seumur hidup': f"{pct_seumur}", 'denda': f"{pct_denda}", 'bebas bersyarat': f"{pct_bebas_bersyarat}", 'bebas dakwaan': f"{pct_bebas_dakwaan}", 'hukuman mati': f"{pct_mati}", 'kontribusi kasus': f"{pct_kasus}" }) # buat DataFrame tabel_ringkasan = pd.DataFrame(summary) WEIGHTS = { 'hukuman mati': 10.0, 'penjara seumur hidup': 8.0, 'penjara': 5.0, 'denda': 1.5, 'bebas bersyarat': -1.0, 'bebas dakwaan': -2.0 } def to_float(x): if x is None: return 0.0 try: v = float(str(x).replace('%','').replace(',','')) if math.isnan(v): return 0.0 return v except: return 0.0 def hitung_score(row): hm = to_float(row['hukuman mati']) sh = to_float(row['penjara seumur hidup']) pj = to_float(row['penjara']) dn = to_float(row['denda']) bb = to_float(row['bebas bersyarat']) bd = to_float(row['bebas dakwaan']) base_score = ( hm * WEIGHTS['hukuman mati'] * 1.2 + sh * WEIGHTS['penjara seumur hidup'] * 1.2 + pj * WEIGHTS['penjara'] * 1.0 + dn * WEIGHTS['denda'] * 1.0 + bb * WEIGHTS['bebas bersyarat'] * 2.0 + bd * WEIGHTS['bebas dakwaan'] * 2.0 ) rata_penjara = to_float(row.get('rata-rata penjara', 0)) penjara_boost = rata_penjara * 4 rata_denda = to_float(row.get('rata-rata denda', 0)) denda_boost = np.log10(rata_denda + 10) * 8 if rata_denda > 0 else 0 return base_score + penjara_boost + denda_boost # --- LANGKAH 1: hitung skor sementara tanpa menyimpan --- semua_skor = tabel_ringkasan.apply(hitung_score, axis=1).tolist() # --- LANGKAH 2: hitung threshold otomatis --- p33 = np.percentile(semua_skor, 33) p66 = np.percentile(semua_skor, 66) # --- LANGKAH 3: fungsi final klasifikasi --- def klasifikasi_pidana(row): score = hitung_score(row) # tidak disimpan #print(f"{row['tindak Pidana']}: score={score:.2f}") if score <= p33: return "light" elif score <= p66: return "moderate" else: return "serious" # --- LANGKAH 4: simpan hanya kategori --- tabel_ringkasan['kategori_pidana'] = tabel_ringkasan.apply(klasifikasi_pidana, axis=1) return tabel_ringkasan def normalize_ringkasan(df): numeric_cols = [ "penjara", "penjara seumur hidup", "denda", "bebas bersyarat", "bebas dakwaan", "hukuman mati", "kontribusi kasus" ] for col in numeric_cols: df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0) return df def table_summary(df): df["kategori_bersih"] = df["amar_lainnya"].apply(kategorikan) # hapus baris yang tidak masuk 5 kategori utama df = df[df["kategori_bersih"].notna()] # Terapkan ke DataFrame df["lama_penjara"], df["banyak_denda"] = zip(*df.apply(proses_amar, axis=1)) tabel = normalize_ringkasan(ringkasan(df)) return tabel