add condition desk
This commit is contained in:
@@ -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"),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user