Skip to content

Commit 1efc35c

Browse files
authored
Refactor data processing with safe type conversion
1 parent bce44d6 commit 1efc35c

1 file changed

Lines changed: 78 additions & 39 deletions

File tree

scripts/build_atlas_data.py

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,110 @@
22
from __future__ import annotations
33

44
import sys
5+
from typing import Any
6+
7+
import pandas as pd
58

69
from common import add_indicators, ensure_dir, parse_args, read_dataset, save_json
710

811

12+
def safe_float(value: Any) -> float | None:
13+
return None if pd.isna(value) else float(value)
14+
15+
16+
def safe_int(value: Any) -> int | None:
17+
return None if pd.isna(value) else int(value)
18+
19+
920
def main() -> int:
10-
parser = parse_args('Genera los archivos consumidos por el atlas interactivo.')
21+
parser = parse_args("Genera los archivos consumidos por el atlas interactivo.")
1122
args = parser.parse_args()
1223

13-
df = add_indicators(read_dataset(args.input)).sort_values(['País', 'Año']).reset_index(drop=True)
14-
out_dir = args.docs_dir / 'atlas' / 'data'
24+
df = (
25+
add_indicators(read_dataset(args.input))
26+
.sort_values(["País", "Año"])
27+
.reset_index(drop=True)
28+
)
29+
30+
out_dir = args.docs_dir / "atlas" / "data"
1531
ensure_dir(out_dir)
1632

1733
records = []
1834
for _, r in df.iterrows():
19-
records.append({
20-
'country': r['País'],
21-
'iso3': r['ISO3'],
22-
'region': r['Región'],
23-
'year': int(r['Año']),
24-
'population_total_millions': float(r['Población_Total_Millones']),
25-
'age_groups_pct': {
26-
'0_14': float(r['Pct_0_14']), '15_24': float(r['Pct_15_24']), '25_54': float(r['Pct_25_54']),
27-
'55_64': float(r['Pct_55_64']), '65_plus': float(r['Pct_65_más']),
35+
record = {
36+
"country": r["País"],
37+
"year": int(r["Año"]),
38+
"population_total_millions": safe_float(r["Población_Total_Millones"]),
39+
"age_groups_pct": {
40+
"0_14": safe_float(r["Pct_0_14"]),
41+
"15_24": safe_float(r["Pct_15_24"]),
42+
"25_54": safe_float(r["Pct_25_54"]),
43+
"55_64": safe_float(r["Pct_55_64"]),
44+
"65_plus": safe_float(r["Pct_65_más"]),
2845
},
29-
'age_groups_thousands': {
30-
'0_14': float(r['Pob_0_14_Miles']), '15_24': float(r['Pob_15_24_Miles']), '25_54': float(r['Pob_25_54_Miles']),
31-
'55_64': float(r['Pob_55_64_Miles']), '65_plus': float(r['Pob_65_más_Miles']),
46+
"age_groups_thousands": {
47+
"0_14": safe_float(r["Pob_0_14_Miles"]),
48+
"15_24": safe_float(r["Pob_15_24_Miles"]),
49+
"25_54": safe_float(r["Pob_25_54_Miles"]),
50+
"55_64": safe_float(r["Pob_55_64_Miles"]),
51+
"65_plus": safe_float(r["Pob_65_más_Miles"]),
3252
},
33-
'indicators': {
34-
'aging_index': None if str(r['Indice_Envejecimiento']) == 'nan' else float(r['Indice_Envejecimiento']),
35-
'dependency_ratio_total': None if str(r['Razon_Dependencia_Total']) == 'nan' else float(r['Razon_Dependencia_Total']),
36-
'dependency_ratio_child': None if str(r['Razon_Dependencia_Infantil']) == 'nan' else float(r['Razon_Dependencia_Infantil']),
37-
'dependency_ratio_older': None if str(r['Razon_Dependencia_Mayores']) == 'nan' else float(r['Razon_Dependencia_Mayores']),
38-
'demographic_dividend_index': None if str(r['Indice_Bono_Demografico']) == 'nan' else float(r['Indice_Bono_Demografico']),
39-
'working_age_pct': float(r['Pct_Edad_Laboral']),
40-
'youth_pct': float(r['Pct_Joven_Total']),
41-
'working_age_thousands': float(r['Pob_Edad_Laboral_Miles']),
42-
'dependent_thousands': float(r['Pob_Dependiente_Miles']),
43-
'aging_change_vs_2000': None if str(r['Cambio_Envejecimiento_vs_2000']) == 'nan' else float(r['Cambio_Envejecimiento_vs_2000']),
53+
"indicators": {
54+
"aging_index": safe_float(r.get("Indice_Envejecimiento")),
55+
"youth_index": safe_float(r.get("Indice_Juventud")),
56+
"dependency_ratio_total": safe_float(r.get("Razon_Dependencia_Total")),
57+
"dependency_ratio_youth": safe_float(r.get("Razon_Dependencia_Juvenil")),
58+
"dependency_ratio_old_age": safe_float(r.get("Razon_Dependencia_Vejez")),
59+
"demographic_dividend_index": safe_float(r.get("Indice_Bono_Demografico")),
60+
"working_age_pct": safe_float(r.get("Pct_Edad_Laboral")),
61+
"youth_pct": safe_float(r.get("Pct_Joven_Total")),
62+
"older_pct": safe_float(r.get("Pct_65_más")),
63+
"working_age_thousands": safe_float(r.get("Pob_Edad_Laboral_Miles")),
64+
"dependent_thousands": safe_float(r.get("Pob_Dependiente_Miles")),
65+
"youth_to_older_ratio": safe_float(r.get("Relacion_Jovenes_Mayores")),
66+
"aging_change_vs_2000": safe_float(r.get("Cambio_Envejecimiento_vs_2000")),
4467
},
45-
'source': r['Fuente'],
46-
})
68+
"source": r["Fuente"],
69+
}
70+
71+
# Solo incluir estas claves si existen en el dataset procesado
72+
if "ISO3" in df.columns:
73+
record["iso3"] = r["ISO3"]
74+
if "Región" in df.columns:
75+
record["region"] = r["Región"]
76+
77+
records.append(record)
4778

4879
metadata = {
49-
'title': 'Atlas Demográfico Interactivo de América Latina',
50-
'author': 'Juan Moisés de la Serna',
51-
'record_count': int(len(df)),
52-
'country_count': int(df['País'].nunique()),
53-
'year_range': [int(df['Año'].min()), int(df['Año'].max())],
54-
'variables': list(df.columns),
80+
"title": "Atlas Demográfico Interactivo de América Latina",
81+
"author": "Juan Moisés de la Serna",
82+
"record_count": int(len(df)),
83+
"country_count": int(df["País"].nunique()),
84+
"year_range": [int(df["Año"].min()), int(df["Año"].max())],
85+
"years": sorted(int(y) for y in df["Año"].dropna().unique()),
86+
"countries": sorted(str(c) for c in df["País"].dropna().unique()),
87+
"variables": list(df.columns),
88+
"source_column": "Fuente",
89+
"dataset_description": (
90+
"Dataset demográfico comparativo con población total, estructura "
91+
"por grupos de edad en porcentaje y población por grupos de edad "
92+
"en miles."
93+
),
5594
}
5695

57-
save_json(out_dir / 'atlas_data.json', {'metadata': metadata, 'records': records})
58-
save_json(out_dir / 'atlas_metadata.json', metadata)
59-
df.to_csv(out_dir / 'atlas_data_with_indicators.csv', index=False, encoding='utf-8-sig')
96+
save_json(out_dir / "atlas_data.json", {"metadata": metadata, "records": records})
97+
save_json(out_dir / "atlas_metadata.json", metadata)
98+
df.to_csv(out_dir / "atlas_data_with_indicators.csv", index=False, encoding="utf-8-sig")
6099

61100
print(f'OK: {out_dir / "atlas_data.json"}')
62101
print(f'OK: {out_dir / "atlas_metadata.json"}')
63102
print(f'OK: {out_dir / "atlas_data_with_indicators.csv"}')
64103
return 0
65104

66105

67-
if __name__ == '__main__':
106+
if __name__ == "__main__":
68107
try:
69108
raise SystemExit(main())
70109
except Exception as exc:
71-
print(f'ERROR: {exc}', file=sys.stderr)
110+
print(f"ERROR: {exc}", file=sys.stderr)
72111
raise

0 commit comments

Comments
 (0)