irhamni commited on
Commit
9ef52f2
·
verified ·
1 Parent(s): aa8a3d6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -84
app.py CHANGED
@@ -696,110 +696,148 @@ def build_faktor_wilayah(df_filtered: pd.DataFrame, pop_kab: pd.DataFrame, pop_p
696
  # 7) AGREGAT WILAYAH × JENIS (Final pakai faktor wilayah)
697
  # ============================================================
698
 
699
- def build_agg_wilayah_jenis(df_filtered: pd.DataFrame, faktor_wilayah: pd.DataFrame, pop_khusus: pd.DataFrame, kew_value: str):
700
- if df_filtered is None or df_filtered.empty:
 
 
 
 
 
701
  return pd.DataFrame()
702
 
703
  kew_norm = str(kew_value or "").upper()
704
- df = df_filtered.copy()
705
 
706
- if "KAB" in kew_norm or "KOTA" in kew_norm:
707
- key_col = "kab_key"
708
- label_col = "KAB_DISP"
709
- label_name = "Kab/Kota"
710
- elif "PROV" in kew_norm:
711
- key_col = "prov_key"
712
- label_col = "PROV_DISP"
713
- label_name = "Provinsi"
714
- else:
715
- key_col = "kab_key"
716
- label_col = "KAB_DISP"
717
- label_name = "Kab/Kota"
718
 
719
- df = df[df["_dataset"].isin(["sekolah", "umum", "khusus"])].copy()
720
- if df.empty:
721
- return pd.DataFrame()
722
 
723
- agg = df.groupby([key_col, label_col, "_dataset"], dropna=False).agg(
724
- Jumlah=("Indeks_Dasar_0_100", "size"),
725
- Rata2_sub_koleksi=("sub_koleksi", "mean"),
726
- Rata2_sub_sdm=("sub_sdm", "mean"),
727
- Rata2_sub_pelayanan=("sub_pelayanan", "mean"),
728
- Rata2_sub_pengelolaan=("sub_pengelolaan", "mean"),
729
- Rata2_dim_kepatuhan=("dim_kepatuhan", "mean"),
730
- Rata2_dim_kinerja=("dim_kinerja", "mean"),
731
- Indeks_Dasar_Agregat_0_100=("Indeks_Dasar_0_100", "mean"),
732
- ).reset_index()
733
 
734
- agg = agg.rename(columns={key_col: "group_key", label_col: label_name, "_dataset": "Jenis"})
 
 
 
735
 
736
- # faktor wilayah (sama untuk semua jenis)
737
- if faktor_wilayah is None or faktor_wilayah.empty:
738
- agg["faktor_penyesuaian_wilayah"] = 1.0
739
- agg["target_total_68"] = np.nan
740
- agg["pop_total"] = np.nan
741
- agg["coverage_total_%"] = np.nan
742
- else:
743
- fw = faktor_wilayah.copy()
744
- keep = ["group_key", label_name, "faktor_penyesuaian", "target_total_68", "pop_total", "coverage_total_%"]
745
- keep = [c for c in keep if c in fw.columns]
746
- fw = fw[keep].rename(columns={"faktor_penyesuaian": "faktor_penyesuaian_wilayah"})
747
- agg = agg.merge(fw, on=["group_key", label_name], how="left")
748
- agg["faktor_penyesuaian_wilayah"] = pd.to_numeric(agg["faktor_penyesuaian_wilayah"], errors="coerce").fillna(1.0)
749
-
750
- agg["faktor_penyesuaian"] = agg["faktor_penyesuaian_wilayah"]
751
- agg["Indeks_Final_Agregat_0_100"] = pd.to_numeric(agg["Indeks_Dasar_Agregat_0_100"], errors="coerce").fillna(0.0) * agg["faktor_penyesuaian"]
752
-
753
- # target/pop/coverage per jenis (hanya khusus, dari POP_KHUSUS) — supaya tidak tampil null -> isi 0
754
- agg["target_total_68_jenis"] = 0.0
755
- agg["pop_total_jenis"] = 0.0
756
- agg["coverage_jenis"] = 0.0
757
-
758
- if (pop_khusus is not None) and (not pop_khusus.empty) and ("KAB" in kew_norm or "KOTA" in kew_norm or kew_norm in {"(SEMUA)", "(SEMUA)".upper()}):
759
- pk = pop_khusus.set_index("kab_key")
760
- for i, r in agg.iterrows():
761
- if str(r.get("Jenis", "")).lower() != "khusus":
762
- continue
763
- gk = r.get("group_key", None)
764
- if gk in pk.index:
765
- t = pk.loc[gk, "Target68_Total_Jenis"] if "Target68_Total_Jenis" in pk.columns else np.nan
766
- p = pk.loc[gk, "Pop_Total_Jenis"] if "Pop_Total_Jenis" in pk.columns else np.nan
767
- if pd.notna(t):
768
- agg.at[i, "target_total_68_jenis"] = float(t)
769
- if pd.notna(p):
770
- agg.at[i, "pop_total_jenis"] = float(p)
771
 
772
- agg["target_total_68_jenis"] = pd.to_numeric(agg["target_total_68_jenis"], errors="coerce").fillna(0.0)
773
- agg["pop_total_jenis"] = pd.to_numeric(agg["pop_total_jenis"], errors="coerce").fillna(0.0)
 
 
 
 
774
 
775
- m_need_pop = (agg["pop_total_jenis"] <= 0) & (agg["target_total_68_jenis"] > 0)
776
- agg.loc[m_need_pop, "pop_total_jenis"] = agg.loc[m_need_pop, "target_total_68_jenis"] / float(FALLBACK_TARGET_RATIO)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
777
 
778
- m2 = agg["pop_total_jenis"] > 0
779
- agg.loc[m2, "coverage_jenis"] = (pd.to_numeric(agg.loc[m2, "Jumlah"], errors="coerce").fillna(0.0) / agg.loc[m2, "pop_total_jenis"]) * 100.0
780
 
781
- # rounding (tampilan konsisten)
782
  for c in [
783
  "Rata2_sub_koleksi","Rata2_sub_sdm","Rata2_sub_pelayanan","Rata2_sub_pengelolaan",
784
  "Rata2_dim_kepatuhan","Rata2_dim_kinerja"
785
  ]:
786
- if c in agg.columns:
787
- agg[c] = pd.to_numeric(agg[c], errors="coerce").fillna(0.0).round(3)
788
-
789
- for c in ["Indeks_Dasar_Agregat_0_100","Indeks_Final_Agregat_0_100"]:
790
- if c in agg.columns:
791
- agg[c] = pd.to_numeric(agg[c], errors="coerce").fillna(0.0).round(2)
792
 
793
- for c in ["faktor_penyesuaian_wilayah","faktor_penyesuaian"]:
794
- if c in agg.columns:
795
- agg[c] = pd.to_numeric(agg[c], errors="coerce").fillna(1.0).round(3)
796
 
797
- for c in ["target_total_68","pop_total","coverage_total_%","target_total_68_jenis","pop_total_jenis","coverage_jenis"]:
798
- if c in agg.columns:
799
- agg[c] = pd.to_numeric(agg[c], errors="coerce").fillna(0.0)
800
 
801
- return agg
 
 
802
 
 
803
 
804
  # ============================================================
805
  # 8) AGREGAT WILAYAH (KESELURUHAN) — RUMUS BARU: AVG3 dari 3 jenis
 
696
  # 7) AGREGAT WILAYAH × JENIS (Final pakai faktor wilayah)
697
  # ============================================================
698
 
699
+ def build_agg_wilayah_total_from_jenis(
700
+ agg_jenis: pd.DataFrame,
701
+ faktor_wilayah: pd.DataFrame,
702
+ pop_khusus: pd.DataFrame, # <-- PATCH: tambah
703
+ kew_value: str
704
+ ):
705
+ if agg_jenis is None or agg_jenis.empty:
706
  return pd.DataFrame()
707
 
708
  kew_norm = str(kew_value or "").upper()
709
+ label_name = "Kab/Kota" if ("KAB" in kew_norm or "KOTA" in kew_norm) else ("Provinsi" if "PROV" in kew_norm else "Kab/Kota")
710
 
711
+ jenis_list = ["sekolah", "umum", "khusus"]
 
 
 
 
 
 
 
 
 
 
 
712
 
713
+ a = agg_jenis.copy()
714
+ a["Jenis"] = a["Jenis"].astype(str).str.lower().str.strip()
 
715
 
716
+ base_keys = a[["group_key", label_name]].drop_duplicates()
 
 
 
 
 
 
 
 
 
717
 
718
+ full = base_keys.assign(_tmp=1).merge(
719
+ pd.DataFrame({"Jenis": jenis_list, "_tmp": 1}),
720
+ on="_tmp"
721
+ ).drop(columns="_tmp")
722
 
723
+ cols_need = [
724
+ "Jumlah",
725
+ "Rata2_sub_koleksi","Rata2_sub_sdm","Rata2_sub_pelayanan","Rata2_sub_pengelolaan",
726
+ "Rata2_dim_kepatuhan","Rata2_dim_kinerja",
727
+ "Indeks_Dasar_Agregat_0_100",
728
+ "Indeks_Final_Agregat_0_100",
729
+ ]
730
+ cols_present = [c for c in cols_need if c in a.columns]
731
+
732
+ full = full.merge(
733
+ a[["group_key", label_name, "Jenis"] + cols_present],
734
+ on=["group_key", label_name, "Jenis"],
735
+ how="left"
736
+ )
737
+
738
+ # missing=0 (kunci avg3 tetap ÷3)
739
+ for c in cols_present:
740
+ full[c] = pd.to_numeric(full[c], errors="coerce").fillna(0.0)
741
+
742
+ # keseluruhan wilayah = avg3 dari 3 jenis
743
+ out = full.groupby(["group_key", label_name], as_index=False).agg(
744
+ n_total=("Jumlah", "sum"),
745
+ Rata2_sub_koleksi=("Rata2_sub_koleksi", "mean"),
746
+ Rata2_sub_sdm=("Rata2_sub_sdm", "mean"),
747
+ Rata2_sub_pelayanan=("Rata2_sub_pelayanan", "mean"),
748
+ Rata2_sub_pengelolaan=("Rata2_sub_pengelolaan", "mean"),
749
+ Rata2_dim_kepatuhan=("Rata2_dim_kepatuhan", "mean"),
750
+ Rata2_dim_kinerja=("Rata2_dim_kinerja", "mean"),
751
+ Indeks_Dasar_Agregat_0_100=("Indeks_Dasar_Agregat_0_100", "mean"),
752
+ Indeks_Final_Wilayah_0_100=("Indeks_Final_Agregat_0_100", "mean"),
753
+ )
 
 
 
 
754
 
755
+ # tempel faktor/target/pop/coverage (informasi verifikasi)
756
+ if faktor_wilayah is not None and not faktor_wilayah.empty:
757
+ fw = faktor_wilayah.copy()
758
+ keep_fw = ["group_key", label_name, "target_total_68", "pop_total", "faktor_penyesuaian", "coverage_total_%"]
759
+ keep_fw = [c for c in keep_fw if c in fw.columns]
760
+ out = out.merge(fw[keep_fw], on=["group_key", label_name], how="left")
761
 
762
+ # =========================================================
763
+ # PATCH UTAMA:
764
+ # Tambahkan target_total_68 & pop_total dari POP_KHUSUS
765
+ # (tanpa kolom khusus tambahan)
766
+ # =========================================================
767
+ if (pop_khusus is not None) and (not pop_khusus.empty):
768
+ pk = pop_khusus.copy()
769
+
770
+ # pastikan numerik
771
+ for c in ["Target68_Total_Jenis", "Pop_Total_Jenis"]:
772
+ if c in pk.columns:
773
+ pk[c] = pd.to_numeric(pk[c], errors="coerce").fillna(0.0)
774
+
775
+ add_df = None
776
+
777
+ # KAB/KOTA: join langsung by kab_key == group_key
778
+ if ("KAB" in kew_norm or "KOTA" in kew_norm):
779
+ if "kab_key" in pk.columns:
780
+ add_df = pk.groupby("kab_key", as_index=False).agg(
781
+ add_target=("Target68_Total_Jenis", "sum"),
782
+ add_pop=("Pop_Total_Jenis", "sum"),
783
+ ).rename(columns={"kab_key": "group_key"})
784
+
785
+ # PROVINSI: agregasi by prov_key == group_key
786
+ elif ("PROV" in kew_norm):
787
+ if "prov_key" in pk.columns:
788
+ add_df = pk.groupby("prov_key", as_index=False).agg(
789
+ add_target=("Target68_Total_Jenis", "sum"),
790
+ add_pop=("Pop_Total_Jenis", "sum"),
791
+ ).rename(columns={"prov_key": "group_key"})
792
+
793
+ if add_df is not None and not add_df.empty:
794
+ out = out.merge(add_df, on="group_key", how="left")
795
+ out["add_target"] = pd.to_numeric(out.get("add_target", 0), errors="coerce").fillna(0.0)
796
+ out["add_pop"] = pd.to_numeric(out.get("add_pop", 0), errors="coerce").fillna(0.0)
797
+
798
+ # tambah ke total existing (kalau belum ada kolomnya -> dianggap 0)
799
+ out["target_total_68"] = pd.to_numeric(out.get("target_total_68", 0), errors="coerce").fillna(0.0) + out["add_target"]
800
+ out["pop_total"] = pd.to_numeric(out.get("pop_total", 0), errors="coerce").fillna(0.0) + out["add_pop"]
801
+
802
+ # opsional tapi konsisten: update coverage & faktor berdasarkan total baru (DI TABEL INI SAJA)
803
+ out["coverage_total_%"] = [
804
+ (safe_div(n, p) * 100) if (p is not None and not pd.isna(p) and float(p) > 0) else 0.0
805
+ for n, p in zip(
806
+ pd.to_numeric(out.get("n_total", 0), errors="coerce").fillna(0).astype(float).tolist(),
807
+ pd.to_numeric(out.get("pop_total", 0), errors="coerce").fillna(0).astype(float).tolist()
808
+ )
809
+ ]
810
+ out["faktor_penyesuaian"] = [
811
+ faktor_penyesuaian_total(n, t)
812
+ for n, t in zip(
813
+ pd.to_numeric(out.get("n_total", 0), errors="coerce").fillna(0).astype(float).tolist(),
814
+ pd.to_numeric(out.get("target_total_68", 0), errors="coerce").fillna(0).astype(float).tolist()
815
+ )
816
+ ]
817
 
818
+ # bersihkan kolom helper
819
+ out = out.drop(columns=[c for c in ["add_target", "add_pop"] if c in out.columns])
820
 
821
+ # rounding (yang sudah ada sebelumnya)
822
  for c in [
823
  "Rata2_sub_koleksi","Rata2_sub_sdm","Rata2_sub_pelayanan","Rata2_sub_pengelolaan",
824
  "Rata2_dim_kepatuhan","Rata2_dim_kinerja"
825
  ]:
826
+ if c in out.columns:
827
+ out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(3)
 
 
 
 
828
 
829
+ for c in ["Indeks_Dasar_Agregat_0_100","Indeks_Final_Wilayah_0_100"]:
830
+ if c in out.columns:
831
+ out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0).round(2)
832
 
833
+ if "faktor_penyesuaian" in out.columns:
834
+ out["faktor_penyesuaian"] = pd.to_numeric(out["faktor_penyesuaian"], errors="coerce").fillna(1.0).round(3)
 
835
 
836
+ for c in ["target_total_68","pop_total","coverage_total_%"]:
837
+ if c in out.columns:
838
+ out[c] = pd.to_numeric(out[c], errors="coerce").fillna(0.0)
839
 
840
+ return out
841
 
842
  # ============================================================
843
  # 8) AGREGAT WILAYAH (KESELURUHAN) — RUMUS BARU: AVG3 dari 3 jenis