PolicyEngine / PolicyEngine/microcosm

Build the Belgian calibration surface by recalibrating the US release recipe

Open
#263 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
4
Avg merge
1d 3h
Merged PRs (30d)
94

Description

Part of #259 (populace-be epic).

What

Recalibrate the US release recipe to a Belgian target surface — as configuration of existing operators, not new code. The US recipe to port: bounded reweighting (start max_weight_ratio=50), capped weighted MAPE with sqrt-value weighting, warm start + target-frame checkpoints (#227), Adam on log-weights, L0 budget mode reserved for a small deliverable variant later.

Target surface (initial, via ledger-be target profiles)

All targets arrive as Ledger profile references (#160 pattern) — populace carries no values. Initial families:

  • Demography: Statbel population by age band × sex × region; national age-band gate mirroring the US demographics.json + base_population_scale posture
  • Fiscal income by commune: Statbel fiscal statistics of income at municipality grain (the flagship open subnational series)
  • Income tax aggregates: SPF Finances/Statbel PIT totals and bracket structure where published
  • Social security: ONSS/RSZ employment and contribution aggregates
  • Caseloads: unemployment (ONEM/RVA), pensions (SFPD), regional child benefit (post-2019 regionalization: caseloads per region)
  • National accounts anchor: NBB household-sector income levels as validation-tier (not hard-calibrated) — apply the levels-sanity lesson from populace#212

Geography spine

  • Commune (NIS code) as finest grain, carried as spine columns — one dataset, filter by geography; no per-area files (the standing architecture decision).
  • Clone-and-assign pool over communes, generalizing the UK OA rowwise operators; collision avoidance between clones.
  • Vintage-aware NIS codes: Belgian municipal mergers change the code set across years — every commune-grain target and assignment records its geography vintage, and mismatched vintages are a compile error, not a silent join (the populace#205 lesson).

Gating posture

National + NUTS1 targets hard-gate; commune rows start diagnostic-only (mirror the US congressional-district posture in populace#204) until the spine demonstrably supports them.

Acceptance

  • Candidate build passes calibration, target_profile_coverage, base_population_scale, and demographics gates on the national + NUTS1 surface.
  • Commune-grain diagnostics render per-target fit (worst-fit communes named).
  • Recipe is entirely spec + profile references; zero BE Python.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the US release recipe, the Ledger profile reference pattern from #160, and the existing calibration gates named in the issue. Check how target profiles, geography vintages, and national plus NUTS1 gating are represented before defining the Belgian spec. Done means the candidate passes the listed gates, commune diagnostics identify worst-fit communes, and no Belgian Python code is added.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.