add condition desk

This commit is contained in:
Debby
2026-06-29 18:16:08 +07:00
parent d379b2c729
commit f738eacbfb
+36 -11
View File
@@ -303,7 +303,7 @@ _PILLAR_CONTEXT_FALLBACK: dict = {
def get_pillar_condition(pillar_name: str, score: float) -> tuple: def get_pillar_condition(pillar_name: str, score: float) -> tuple:
""" """
Mengembalikan (condition_en, condition_id) berdasarkan skor dan nama pilar. Mengembalikan 4-tuple kondisi pilar berdasarkan skor dan nama pilar.
Tier mengacu GFSI 2022 (Economist Impact) + IPC Phase Classification (2019): Tier mengacu GFSI 2022 (Economist Impact) + IPC Phase Classification (2019):
>= 75 -> Secure / Aman >= 75 -> Secure / Aman
@@ -320,10 +320,15 @@ def get_pillar_condition(pillar_name: str, score: float) -> tuple:
score : Skor ternormalisasi skala 1-100. score : Skor ternormalisasi skala 1-100.
Returns: Returns:
Tuple (condition_en: str, condition_id: str) Tuple (
condition_en : str — label tier bahasa Inggris, e.g. "At Risk"
condition_id : str — label tier bahasa Indonesia, e.g. "Berisiko"
condition_desc_en : str — deskripsi kontekstual bahasa Inggris
condition_desc_id : str — deskripsi kontekstual bahasa Indonesia
)
""" """
if score is None or (isinstance(score, float) and np.isnan(score)): if score is None or (isinstance(score, float) and np.isnan(score)):
return ("N/A", "N/A") return ("N/A", "N/A", "N/A", "N/A")
# Tentukan tier # Tentukan tier
tier_label_en = _CONDITION_TIERS[-1][1] # default: Critical tier_label_en = _CONDITION_TIERS[-1][1] # default: Critical
@@ -334,7 +339,7 @@ def get_pillar_condition(pillar_name: str, score: float) -> tuple:
tier_label_id = lbl_id tier_label_id = lbl_id
break break
# Ambil konteks per pilar # Ambil deskripsi kontekstual per pilar
ctx = _PILLAR_CONTEXT.get(pillar_name, None) ctx = _PILLAR_CONTEXT.get(pillar_name, None)
if ctx: if ctx:
ctx_en, ctx_id = ctx.get( ctx_en, ctx_id = ctx.get(
@@ -344,10 +349,7 @@ def get_pillar_condition(pillar_name: str, score: float) -> tuple:
else: else:
ctx_en, ctx_id = _PILLAR_CONTEXT_FALLBACK.get(tier_label_en, ("", "")) ctx_en, ctx_id = _PILLAR_CONTEXT_FALLBACK.get(tier_label_en, ("", ""))
# Format akhir: "TIER — Context" return tier_label_en, tier_label_id, ctx_en, ctx_id
condition_en = f"{tier_label_en}{ctx_en}"
condition_id = f"{tier_label_id}{ctx_id}"
return condition_en, condition_id
# ============================================================================= # =============================================================================
@@ -938,11 +940,17 @@ class FoodSecurityAggregator:
df["pillar_country_score_1_100"] = global_minmax(df["pillar_country_norm"]) df["pillar_country_score_1_100"] = global_minmax(df["pillar_country_norm"])
# --------------------------------------------------------------- # ---------------------------------------------------------------
# TAMBAHAN: kolom kondisi pilar # TAMBAHAN: kolom kondisi pilar (tier + deskripsi dipisah)
# Dibangkitkan SETELAH score_1_100 tersedia, sehingga tier # Dibangkitkan SETELAH score_1_100 tersedia, sehingga tier
# langsung mencerminkan skor dalam skala akhir 1-100. # langsung mencerminkan skor dalam skala akhir 1-100.
# Referensi tier: GFSI 2022 (Economist Impact); IPC 2019; # Referensi tier: GFSI 2022 (Economist Impact); IPC 2019;
# FAO/CFS 1996/2009; FAO SOFI 2024. # FAO/CFS 1996/2009; FAO SOFI 2024.
#
# Kolom yang dihasilkan:
# pillar_condition_en — label tier EN, e.g. "At Risk"
# pillar_condition_id — label tier ID, e.g. "Berisiko"
# pillar_condition_desc_en — deskripsi kontekstual EN
# pillar_condition_desc_id — deskripsi kontekstual ID
# --------------------------------------------------------------- # ---------------------------------------------------------------
conditions = df.apply( conditions = df.apply(
lambda row: get_pillar_condition( lambda row: get_pillar_condition(
@@ -953,6 +961,8 @@ class FoodSecurityAggregator:
) )
df["pillar_condition_en"] = conditions.apply(lambda x: x[0]) df["pillar_condition_en"] = conditions.apply(lambda x: x[0])
df["pillar_condition_id"] = conditions.apply(lambda x: x[1]) df["pillar_condition_id"] = conditions.apply(lambda x: x[1])
df["pillar_condition_desc_en"] = conditions.apply(lambda x: x[2])
df["pillar_condition_desc_id"] = conditions.apply(lambda x: x[3])
# Rank hanya di antara negara asli # Rank hanya di antara negara asli
country_only = df[df["country_id"] != ASEAN_COUNTRY_ID].copy() country_only = df[df["country_id"] != ASEAN_COUNTRY_ID].copy()
@@ -978,6 +988,8 @@ class FoodSecurityAggregator:
df["country_name_id"] = df["country_name_id"].astype(str) df["country_name_id"] = df["country_name_id"].astype(str)
df["pillar_condition_en"] = df["pillar_condition_en"].astype(str) df["pillar_condition_en"] = df["pillar_condition_en"].astype(str)
df["pillar_condition_id"] = df["pillar_condition_id"].astype(str) df["pillar_condition_id"] = df["pillar_condition_id"].astype(str)
df["pillar_condition_desc_en"] = df["pillar_condition_desc_en"].astype(str)
df["pillar_condition_desc_id"] = df["pillar_condition_desc_id"].astype(str)
self.logger.info( self.logger.info(
f" Total rows: {len(df):,} " f" Total rows: {len(df):,} "
@@ -1002,10 +1014,13 @@ class FoodSecurityAggregator:
bigquery.SchemaField("pillar_country_score_1_100", "FLOAT", mode="REQUIRED"), bigquery.SchemaField("pillar_country_score_1_100", "FLOAT", mode="REQUIRED"),
bigquery.SchemaField("rank_in_pillar_year", "INTEGER", mode="REQUIRED"), bigquery.SchemaField("rank_in_pillar_year", "INTEGER", mode="REQUIRED"),
bigquery.SchemaField("year_over_year_change", "FLOAT", mode="NULLABLE"), bigquery.SchemaField("year_over_year_change", "FLOAT", mode="NULLABLE"),
# --- KOLOM KONDISI BARU --- # --- KOLOM KONDISI ---
# Tier skor (GFSI 2022) + konteks substantif per pilar (FAO/CFS; IPC 2019) # Tier label (GFSI 2022): Secure / Adequate / Moderate / At Risk / Critical
bigquery.SchemaField("pillar_condition_en", "STRING", mode="REQUIRED"), bigquery.SchemaField("pillar_condition_en", "STRING", mode="REQUIRED"),
bigquery.SchemaField("pillar_condition_id", "STRING", mode="REQUIRED"), bigquery.SchemaField("pillar_condition_id", "STRING", mode="REQUIRED"),
# Deskripsi kontekstual per pilar (FAO/CFS 4-pillar; IPC 2019; FAO SOFI 2024)
bigquery.SchemaField("pillar_condition_desc_en", "STRING", mode="REQUIRED"),
bigquery.SchemaField("pillar_condition_desc_id", "STRING", mode="REQUIRED"),
] ]
rows = load_to_bigquery( rows = load_to_bigquery(
self.client, df, table_name, layer='gold', self.client, df, table_name, layer='gold',
@@ -1315,6 +1330,8 @@ class FoodSecurityAggregator:
# Ambil kondisi dari kolom yang sudah dihitung di df_pillar_by_country # Ambil kondisi dari kolom yang sudah dihitung di df_pillar_by_country
cond_en = str(row.get("pillar_condition_en", "N/A")) cond_en = str(row.get("pillar_condition_en", "N/A"))
cond_id = str(row.get("pillar_condition_id", "N/A")) cond_id = str(row.get("pillar_condition_id", "N/A"))
cond_desc_en = str(row.get("pillar_condition_desc_en", "N/A"))
cond_desc_id = str(row.get("pillar_condition_desc_id", "N/A"))
records.append({ records.append({
"year": yr, "year": yr,
@@ -1336,6 +1353,8 @@ class FoodSecurityAggregator:
"is_asean_aggregate": is_asean, "is_asean_aggregate": is_asean,
"pillar_condition_en": cond_en, "pillar_condition_en": cond_en,
"pillar_condition_id": cond_id, "pillar_condition_id": cond_id,
"pillar_condition_desc_en": cond_desc_en,
"pillar_condition_desc_id": cond_desc_id,
"narrative_en": narrative_en, "narrative_en": narrative_en,
"narrative_id": narrative_id, "narrative_id": narrative_id,
}) })
@@ -1350,6 +1369,8 @@ class FoodSecurityAggregator:
df["country_name_id"] = df["country_name_id"].astype(str) df["country_name_id"] = df["country_name_id"].astype(str)
df["pillar_condition_en"] = df["pillar_condition_en"].astype(str) df["pillar_condition_en"] = df["pillar_condition_en"].astype(str)
df["pillar_condition_id"] = df["pillar_condition_id"].astype(str) df["pillar_condition_id"] = df["pillar_condition_id"].astype(str)
df["pillar_condition_desc_en"] = df["pillar_condition_desc_en"].astype(str)
df["pillar_condition_desc_id"] = df["pillar_condition_desc_id"].astype(str)
df["narrative_en"] = df["narrative_en"].astype(str) df["narrative_en"] = df["narrative_en"].astype(str)
df["narrative_id"] = df["narrative_id"].astype(str) df["narrative_id"] = df["narrative_id"].astype(str)
for col in ["pillar_score", "yoy_change", "top_country_score", "bottom_country_score"]: for col in ["pillar_score", "yoy_change", "top_country_score", "bottom_country_score"]:
@@ -1377,8 +1398,12 @@ class FoodSecurityAggregator:
bigquery.SchemaField("bottom_country_id", "STRING", mode="NULLABLE"), bigquery.SchemaField("bottom_country_id", "STRING", mode="NULLABLE"),
bigquery.SchemaField("bottom_country_score", "FLOAT", mode="NULLABLE"), bigquery.SchemaField("bottom_country_score", "FLOAT", mode="NULLABLE"),
bigquery.SchemaField("is_asean_aggregate", "BOOL", mode="REQUIRED"), bigquery.SchemaField("is_asean_aggregate", "BOOL", mode="REQUIRED"),
# Tier label: Secure / Adequate / Moderate / At Risk / Critical
bigquery.SchemaField("pillar_condition_en", "STRING", mode="REQUIRED"), bigquery.SchemaField("pillar_condition_en", "STRING", mode="REQUIRED"),
bigquery.SchemaField("pillar_condition_id", "STRING", mode="REQUIRED"), bigquery.SchemaField("pillar_condition_id", "STRING", mode="REQUIRED"),
# Deskripsi kontekstual per pilar
bigquery.SchemaField("pillar_condition_desc_en", "STRING", mode="REQUIRED"),
bigquery.SchemaField("pillar_condition_desc_id", "STRING", mode="REQUIRED"),
bigquery.SchemaField("narrative_en", "STRING", mode="REQUIRED"), bigquery.SchemaField("narrative_en", "STRING", mode="REQUIRED"),
bigquery.SchemaField("narrative_id", "STRING", mode="REQUIRED"), bigquery.SchemaField("narrative_id", "STRING", mode="REQUIRED"),
] ]