Do the Setup, if you have not yet done so.
Start a new R script and copy in this starter code (it loads the packages and downloads both data sets — we walked through every line on the slides):
pacman::p_load(
tidyverse, # Data manipulation & figures
wbstats, # World Bank data via API
vdemdata, # Varieties of Democracy data
estimatr, # OLS with robust standard errors
modelsummary # Nicely formatted regression tables
)
# V-Dem: civil liberties, and state ownership of the economy
Dat_vdem <- vdem %>%
as_tibble() %>%
select(country_text_id, year,
civ_liberties = v2xcl_rol, # Equality before the law & individual liberty
state_own_raw = v2clstown) %>% # State ownership of the economy
mutate(state_ownership = -state_own_raw) # Reverse: higher = MORE state ownership
# World Bank: extreme poverty (share below $3.00 a day, 2021 PPP).
# Try the live API; if it is down, fall back to the cached copy.
Dat_poverty <- tryCatch(
wb_data("SI.POV.DDAY", start_date = 1972, end_date = 2025),
error = function(e) readRDS("data/wb_poverty_raw.rds")
) %>%
rename(poverty = SI.POV.DDAY,
year = date,
country_text_id = iso3c) %>%
select(country_text_id, year, country, poverty) %>%
drop_na(poverty) %>%
group_by(country) %>%
filter(year == max(year)) %>% # Keep the most recent estimate per country
ungroup()
Dat_poverty and Dat_vdem into one tibble
called Dat. Think first: which join do you want,
and which variables form the key?We want only countries that appear in both tibbles (an inner join), and a country is identified by its ISO code together with the year.
Dat <- inner_join(Dat_poverty, Dat_vdem, by = c("country_text_id", "year"))
Stuck?
- Did the
pacman::p_load(...)line run without red error messages? If not, fix that first.- Strange results? Clear leftovers with a fresh start: Session → Restart R, then rerun your script from the top.
- World Bank API down or very slow? Load our cached copy instead:
Dat <- readRDS(url("https://willowy-quokka-e604ee.netlify.app/data/Dat_L2.rds"))- Still stuck? Ask (and answer!) in the t-R-ouble forum on Absalon.
ggplot(data = Dat, aes(y = poverty, x = civ_liberties)) +
geom_text(aes(label = country)) +
labs(y = "% of population below $3.00 a day (2021 PPP)",
x = "Civil liberties") +
theme_minimal()
Before you compute anything: judging only from your scatter plot, the correlation between poverty and civil liberties is …
Now check yourself: estimate the correlation with
cor() (rounded to two digits; point or comma is fine):
Dat %>%
select(poverty, civ_liberties) %>%
cor() %>%
round(2)
# poverty civ_liberties
# poverty 1.00 -0.33
# civ_liberties -0.33 1.00
This is edge ② of our triangle. What does the correlation suggest about a liberty–equality trade-off?
Write one sentence in your R script (as a
# comment) interpreting the correlation — as if for your
term paper. Then compare with the model answer:
Across 161 countries, civil liberties correlate moderately negatively with extreme poverty (r ≈ -0.33): countries with stronger civil liberties tend to have a smaller share of their population in extreme poverty.
(Yours doesn't need the same words — but it should name the direction, the rough strength, and the units of analysis (countries), and it should not claim causality.)
Bonus (for the fast): Dat has ~160
countries, but V-Dem covers 179 — where did the rest go? Find the
countries we lost in the join, using anti_join().
Why are they missing?
Dat_vdem %>%
filter(year > 2015) %>% # Recent years only
anti_join(Dat_poverty, by = c("country_text_id", "year")) %>%
distinct(country_text_id)
# # A tibble: 179 × 1
# country_text_id
# <chr>
# 1 MEX
# 2 SUR
# 3 SWE
# 4 CHE
# 5 GHA
# 6 ZAF
# 7 JPN
# 8 MMR
# 9 RUS
# 10 ALB
# # ℹ 169 more rows
They are countries (and country-years) with no World Bank
poverty estimate — poverty data require household surveys,
which some countries run rarely or not at all (e.g. North Korea). An
inner_join() silently drops them. Data that are
missing are a finding, too: our analysis can only speak about
countries that measure poverty.