This file is not education data itself — it’s the country
reference table that sits behind the World Bank’s EdStats
(Education Statistics) database. Every actual indicator table in EdStats
(literacy rates, enrollment, spending, etc.) joins back to this file by
CountryCode to know which region a country belongs to, what
income group it’s classified in, which statistical standards it follows,
and dozens of other metadata facts. Understood on its own, it’s a useful
snapshot of how the World Bank organizes and classifies the
world’s economies — 234 rows covering both individual countries
and the regional/income aggregates used to summarize them.
# NOTE: the original World Bank export is ISO-8859-1 encoded. If you re-download
# the source file yourself, read it with locale(encoding = "ISO-8859-1") or
# convert to UTF-8 first (e.g. iconv -f ISO-8859-1 -t UTF-8) to avoid errors.
raw <- read_csv("EDSTATS_Country.csv", col_types = cols(.default = "c"))
# Rows with no Region are the aggregate/grouping rows (World, income groups,
# regional roll-ups) rather than individual countries.
countries <- raw %>% filter(!is.na(Region))
aggregates <- raw %>% filter(is.na(Region))
tibble(
Metric = c("Total rows", "Individual countries/economies", "Regional & income-group aggregate rows",
"Columns of metadata"),
Value = c(nrow(raw), nrow(countries), nrow(aggregates), ncol(raw))
) %>%
kable(caption = "Dataset snapshot") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Metric | Value |
|---|---|
| Total rows | 234 |
| Individual countries/economies | 210 |
| Regional & income-group aggregate rows | 24 |
| Columns of metadata | 31 |
Of the 31 columns, most describe statistical methodology and reporting practices rather than economic outcomes: what year a country’s national accounts are based on, which System of National Accounts version it follows, whether it publishes to the IMF’s data dissemination standard, and when its most recent population census, household survey, or agricultural census took place. This makes the file most useful as a data-quality and comparability guide — a reminder that not every country’s statistics are collected the same way or as recently as others.
region_income <- countries %>%
count(Region, `Income Group`) %>%
filter(!is.na(`Income Group`))
income_order <- c("Low income", "Lower middle income", "Upper middle income",
"High income: nonOECD", "High income: OECD")
ggplot(region_income %>% mutate(`Income Group` = factor(`Income Group`, levels = income_order)),
aes(x = fct_reorder(Region, n, sum), y = n, fill = `Income Group`)) +
geom_col() +
coord_flip() +
scale_fill_brewer(palette = "RdYlBu", direction = -1) +
labs(title = "Countries by region and income group",
x = NULL, y = "Number of countries", fill = "Income group") +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
countries %>%
count(Region, sort = TRUE) %>%
mutate(share = percent(n / sum(n), accuracy = 0.1)) %>%
kable(col.names = c("Region", "Countries", "Share"), caption = "Countries by World Bank region") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Region | Countries | Share |
|---|---|---|
| Europe & Central Asia | 57 | 27.1% |
| Sub-Saharan Africa | 47 | 22.4% |
| Latin America & Caribbean | 38 | 18.1% |
| East Asia & Pacific | 36 | 17.1% |
| Middle East & North Africa | 21 | 10.0% |
| South Asia | 8 | 3.8% |
| North America | 3 | 1.4% |
Europe & Central Asia (57 countries) and Sub-Saharan Africa (47) are the two largest regional groupings, together accounting for exactly half of all classified countries — a reflection of how many small post-Soviet and African states exist relative to other regions, not a statement about population or economic weight. Income classification skews toward the lower half: low, lower-middle, and upper-middle income countries together make up about 62% of classified economies, while OECD high-income countries are the smallest single group (30 countries).
countries %>%
filter(!is.na(`Income Group`)) %>%
count(Region, `Income Group`) %>%
pivot_wider(names_from = `Income Group`, values_from = n, values_fill = 0) %>%
kable(caption = "Income group composition of each region") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
scroll_box(width = "100%")
| Region | High income: OECD | High income: nonOECD | Low income | Lower middle income | Upper middle income |
|---|---|---|---|---|---|
| East Asia & Pacific | 4 | 8 | 5 | 15 | 4 |
| Europe & Central Asia | 23 | 12 | 2 | 7 | 13 |
| Latin America & Caribbean | 0 | 8 | 1 | 9 | 20 |
| Middle East & North Africa | 1 | 7 | 0 | 9 | 4 |
| North America | 2 | 1 | 0 | 0 | 0 |
| South Asia | 0 | 0 | 3 | 5 | 0 |
| Sub-Saharan Africa | 0 | 1 | 29 | 11 | 6 |
The regional/income cross-tabulation shows sharp structural differences: Sub-Saharan Africa is almost entirely low- and lower-middle income (no OECD high-income members at all), while Europe & Central Asia spans the full income spectrum, from low-income Central Asian states to some of the wealthiest OECD economies in the world — the most economically diverse region in the file. North America’s 3 members are entirely high-income, as expected.
lending_summary <- countries %>%
mutate(`Lending category` = coalesce(`Lending category`, "Not applicable (high-income)")) %>%
count(`Lending category`, sort = TRUE) %>%
mutate(share = percent(n / sum(n), accuracy = 0.1))
lending_summary %>%
kable(col.names = c("Lending Category", "Countries", "Share"),
caption = "World Bank lending category") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Lending Category | Countries | Share |
|---|---|---|
| Not applicable (high-income) | 68 | 32.4% |
| IBRD | 63 | 30.0% |
| IDA | 63 | 30.0% |
| Blend | 16 | 7.6% |
The lending category identifies which arm of the World Bank Group a country borrows from: IBRD (International Bank for Reconstruction and Development) serves middle-income and creditworthy countries, IDA (International Development Association) serves the poorest countries with concessional financing, and Blend countries qualify for both. 63 countries fall into each of IBRD and IDA, with 16 “Blend” countries qualifying for both — and the 92 countries with no lending category are, almost entirely, high-income countries that don’t borrow from the Bank at all.
standards <- tibble(
Standard = c("IMF Special Data Dissemination Standard (SDDS)",
"IMF General Data Dissemination System (GDDS)",
"System of National Accounts 1993",
"Vital registration system complete"),
`Countries reporting` = c(
sum(countries$`IMF data dissemination standard` == "SDDS", na.rm = TRUE),
sum(countries$`IMF data dissemination standard` == "GDDS", na.rm = TRUE),
sum(countries$`System of National Accounts` == "1993", na.rm = TRUE),
sum(countries$`Vital registration complete` == "Yes", na.rm = TRUE)
)
)
standards %>%
kable(caption = "Adoption of key international statistical standards") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Standard | Countries reporting |
|---|---|
| IMF Special Data Dissemination Standard (SDDS) | 68 |
| IMF General Data Dissemination System (GDDS) | 95 |
| System of National Accounts 1993 | 85 |
| Vital registration system complete | 103 |
These four fields are effectively a data-quality signal for every other World Bank indicator table: a country following the stricter SDDS standard, using the modern 1993 System of National Accounts, and maintaining complete vital registration is one whose statistics (education, health, economic) can generally be trusted more readily than a country reporting under the looser GDDS standard with an incomplete vital registration system. Only about half of countries with recorded values have a complete vital registration system — a reminder that even basic counts like births and deaths are not uniformly well-measured worldwide, let alone more complex education indicators like literacy or enrollment.
ppp_years <- countries %>%
filter(!is.na(`PPP survey year`)) %>%
count(`PPP survey year`)
ppp_years %>%
kable(col.names = c("PPP Survey Year", "Countries"),
caption = "Purchasing Power Parity (PPP) survey year") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| PPP Survey Year | Countries |
|---|---|
| 2005 | 145 |
Every country with a recorded PPP survey year in this file used the 2005 International Comparison Program round — meaning any purchasing-power-parity-adjusted figures drawing on this vintage of World Bank data share a common price-comparison baseline, which matters for anyone chaining PPP-adjusted indicators together across countries.
aggregates %>%
select(CountryCode, `Short Name`) %>%
kable(caption = "Non-country rows: regional and income-group aggregates used elsewhere in EdStats") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
scroll_box(height = "350px")
| CountryCode | Short Name |
|---|---|
| EAP | East Asia & Pacific (developing only) |
| EAS | East Asia & Pacific (all income levels) |
| ECA | Europe & Central Asia (developing only) |
| ECS | Europe & Central Asia (all income levels) |
| EMU | Euro area |
| HIC | High income |
| HPC | Heavily indebted poor countries (HIPC) |
| LAC | Latin America & Caribbean (developing only) |
| LCN | Latin America & Caribbean (all income levels) |
| LDC | Least developed countries: UN classification |
| LIC | Low income |
| LMC | Lower middle income |
| LMY | Low & middle income |
| MEA | Middle East & North Africa (all income levels) |
| MIC | Middle income |
| MNA | Middle East & North Africa (developing only) |
| NAC | North America |
| NOC | High income: nonOECD |
| OEC | High income: OECD |
| SAS | South Asia |
| SSA | Sub-Saharan Africa (developing only) |
| SSF | Sub-Saharan Africa (all income levels) |
| UMC | Upper middle income |
| WLD | World |
These 24 rows are not countries — they’re the codes (WLD
for World, LIC for Low income, SSF for
Sub-Saharan Africa “all income levels,” etc.) that the World Bank uses
to report regional and income-group totals in the
actual indicator tables. Some regions appear twice, once as “developing
only” (e.g. SSA) and once as “all income levels”
(e.g. SSF) — a distinction worth watching for when joining
or filtering EdStats indicator data, since accidentally including both
versions of the same region in a sum would double-count.
countries %>%
select(CountryCode, `Short Name`, Region, `Income Group`, `Lending category`, `Currency Unit`) %>%
datatable(options = list(pageLength = 15, scrollX = TRUE), rownames = FALSE, filter = "top")
This file captures a single snapshot in time of the
World Bank’s country classifications — income group and region
assignments are periodically revised (a country can move between income
tiers as its economy grows), so this table should be treated as a
specific vintage rather than a permanently fixed reference. It also
contains no indicator values itself; any substantive claim about
education outcomes requires joining this file to the actual EdStats
indicator tables by CountryCode.