How to split disbursements across SDG goals
Calculate per-goal or per-target disbursement totals from a get_tossd frame, weighted so activities tagged with multiple SDG codes count fractionally across each goal.
Steps
-
Query data using the
"analysis"column preset. Bothsdg_totalsandexplode_sdgreadsdg_codes_raw, which is included in the"analysis"preset. The"minimal"preset omits it. -
Explode SDG codes for row-level analysis. The
sdg_codes_rawcolumn packs one or more semicolon-delimited codes per activity, combining goals (4) and targets (4.2). The TOSSD Reporting Instructions cap dissemination at the first ten SDG targets or goals reported per activity, so activities with more tags show only the first ten.explode_sdggives each code its own row and assigns an equal weightsdg_weightof1/nacross thenreported codes. Passvalue=to generate a precomputed{value}_weightedcolumn alongside the untouched original.ex = df.tossd.explode_sdg(value="usd_disbursement") ex[ ["sdg_code", "sdg_goal", "sdg_is_target", "sdg_weight", "usd_disbursement_weighted"] ].head()sdg_code sdg_goal sdg_is_target sdg_weight usd_disbursement_weighted 0 4.2 4 True 0.25 0.002704 1 13 13 False 0.25 0.002704 2 10 10 False 0.25 0.002704 3 1 1 False 0.25 0.002704 4 5 5 False 0.50 0.008104The
sdg_goalcolumn extracts the integer goal number, grouping target-level tags like4.2and goal-level tags like13under their primary goal. Summingusd_disbursement_weightedrestores each activity's original disbursement total. -
Calculate weighted disbursements per goal with
df.tossd.sdg_totals(). This method runs the explode-and-weight process internally, allocating a multi-tagged activity's disbursement proportionally across its goals. It excludesis_aggregaterows by default (include_aggregates=False).sdg_goal usd_disbursement share_pct rank 0 17 50855.509935 18.453846 1 1 3 26973.450607 9.787807 2 2 13 24788.626611 8.995003 3 3 1 21036.438058 7.633454 4 4 9 20760.196998 7.533215 5The
share_pctcolumn reports each goal's share of the weighted total (0-100, unrounded) and sums to 100 across the full result before applying anytop=truncation. That weighted total equals the SDG-tagged subset of the included rows'usd_disbursement, as activities with no SDG tag (an empty or nullsdg_codes_raw) contribute zero to goal totals.Pass
level="code"to obtain target-level detail.sdg_code usd_disbursement share_pct rank 0 17 29297.097592 10.630984 1 1 13 12618.315801 4.578785 2 2 17.3 12317.547051 4.469646 3 3 9 9459.240859 3.432457 4 4 16 8412.056263 3.052467 5The publisher formats some goal-level tags with a trailing
.0token ("17.0","16.0","1.0","9.0"in the 2024 file). Settinglevel="code"preserves each distinct token as its own row. Settinglevel="goal"(the default) folds these into their respective goals alongside standard goal-level tags.
Verify it worked
Compare the SDG-tagged total to the non-aggregate total in df.
tagged = df.tossd.sdg_totals()["usd_disbursement"].sum()
non_aggregate = df.tossd.exclude_aggregates()["usd_disbursement"].sum()
print(round(tagged / non_aggregate * 100, 1))
In this dataset, 69.2% of non-aggregate disbursements carry at least one SDG tag. The remainder contain no sdg_codes_raw entry.
Troubleshooting
ValueError naming sdg_codes_raw. Both sdg_totals and explode_sdg require sdg_codes_raw. Re-query with columns="analysis" or add sdg_codes_raw to your explicit column list.
ValueError: sdg_totals() needs column(s) sdg_codes_raw, not present in df. Re-query with columns='analysis', or add sdg_codes_raw to your columns= list.
ValueError naming sdg_code, sdg_goal, sdg_is_target, or sdg_weight. Both explode_sdg and sdg_totals reject a DataFrame that already contains these columns to prevent duplicate weighting. Pass the original get_tossd frame.
See also
- Helpers reference for
explode_sdgparameter definitions and weighting rules. - Columns, presets, and units for columns included in the
"analysis"preset.