Python packages / tossd-reader / How-to guides
Aggregate by recipient country groups
Group recipient countries into standard classifications (Least Developed Countries, World Bank income tiers, or UN regions) with df.tossd.add_recipient_group(scheme=...). The method reads from a packaged, versioned table and retains regional and multi-country flows in an explicit category.
Steps
-
Add recipient groups with
add_recipient_group(scheme="ldc").import tossd_reader as tossd df = tossd.get_tossd(years=2024, columns="analysis", units="usd_million") rg = df.tossd.add_recipient_group(scheme="ldc") rg.groupby("recipient_group", observed=True)["usd_disbursement"].sum().round(1)recipient_group Least Developed Countries 88056.9 Other Developing Countries 262225.0 Regional / Multi-country Unallocated 147394.1 Name: usd_disbursement, dtype: float64The three totals sum to USD 497.7 billion, matching the published 2024 total, because
dfincludes both pillars and publisher-computed aggregate rows. Most ofRegional / Multi-country Unallocated(USD 116.0 billion of the 147.4 billion) represents Pillar II expenditures, which are regional or global programmes that do not allocate to an individual recipient country. The remainder comprises regional Pillar I flows without a single-country ISO3 code and the aggregate rows' share. -
Filter to Pillar I to isolate cross-border flows. To analyse country-level development finance, filter before grouping.
df1 = tossd.get_tossd(years=2024, pillars=1, columns="analysis", units="usd_million") df1 = df1[~df1["is_aggregate"]] rg1 = df1.tossd.add_recipient_group(scheme="ldc") rg1.groupby("recipient_group", observed=True)["usd_disbursement"].sum().round(1)recipient_group Least Developed Countries 64164.4 Other Developing Countries 181696.6 Regional / Multi-country Unallocated 30704.2 Name: usd_disbursement, dtype: float64Regional / Multi-country Unallocatedaccounts for 11.1% of the Pillar I total once aggregate rows are excluded. -
Switch classification schemes with
scheme="income"orscheme="region".df.tossd.add_recipient_group(scheme="income").groupby("recipient_group", observed=True)[ "usd_disbursement" ].sum().round(1)recipient_group High income 5629.8 Low income 60718.1 Lower middle income 119897.5 Regional / Multi-country Unallocated 147394.1 Unclassified 350.8 Upper middle income 163685.6 Name: usd_disbursement, dtype: float64Unclassified(USD 350.8 million) covers six non-self-governing territories for which the World Bank publishes no independent income classification: Saint Helena, Montserrat, the Cook Islands, Niue, Tokelau, and Wallis and Futuna. These are single-territory recipient codes distinct fromRegional / Multi-country Unallocated.scheme="region"classifies all rows directly because TOSSD assigns a UN region to every recipient code, including regional groupings.df.tossd.add_recipient_group(scheme="region").groupby("recipient_group", observed=True)[ "usd_disbursement" ].sum().round(1).sort_values(ascending=False).head(5)recipient_group South of Sahara 94764.2 Europe 85502.9 Developing countries, unspecified 85462.3 South & Central Asia 59971.0 Global 42160.4 Name: usd_disbursement, dtype: float64 -
Account for the São Tomé and Príncipe LDC graduation in 2024 analysis. São Tomé and Príncipe (
recipient_code268) graduated from LDC status on 13 December 2024. The packaged table reflects the current LDC list, classifying all 2024 rows asOther Developing Countries.rg.loc[rg["recipient_code"] == 268, "recipient_group"].unique()['Other Developing Countries'] Categories (3, str): ['Least Developed Countries', 'Other Developing Countries', 'Regional / Multi-country Unallocated']When reconciling against a 2024-vintage LDC classification, treat São Tomé and Príncipe as an LDC for reporting periods prior to graduation.
rg.loc[rg["recipient_code"] == 268, "recipient_group"] = "Least Developed Countries" -
Cite the classification vintage with
get_recipient_groups_version().tossd.get_recipient_groups_version()'ldc-2024review/wb-fy27'The identifier specifies the UN LDC-list vintage and the World Bank income classification fiscal year. Record this version tag alongside published figures.
Verify it worked
Every recipient code resolves to a classification group, and the grouped totals sum back to the original dataset total.
grand_total = round(df["usd_disbursement"].sum(), 1)
group_total = round(
rg.groupby("recipient_group", observed=True)["usd_disbursement"].sum().sum(), 1
)
print(group_total == grand_total)
True
Troubleshooting
ValueError naming a scheme. Pass "ldc", "income", or "region".
df.tossd.add_recipient_group(scheme="ld")
ValueError: add_recipient_group() scheme='ld' is not one of 'income', 'ldc', 'region'.
UserWarning for unmapped recipient_code values. If a query returns recipient codes newer than the packaged snapshot table, those rows receive NA in recipient_group while the rest of the dataset remains valid.
See also
- Helpers reference for
add_recipient_group()parameter specifications. - Rank providers by disbursement for disaggregating flows by donor institution.
- Join TOSSD to other country datasets for merging external indicators using ISO3 codes.
- Pillars and aggregate rows for handling
is_aggregaterows.