Introduction

For my first dataset, I selected life expectancy data from the World Bank. I explored how life expectancy changed across different countries before, during, and after the COVID-19 pandemic. My main goal was to understand whether countries recovered at the same rate or whether some continued to experience lower life expectancy.

Data Source

The dataset comes from the World Bank’s World Development Indicators database.

The original dataset contains countries, regional aggregates, and separate columns for each year. I also used country metadata to identify regions and income groups.

Research Question

How did life expectancy change between 2019 and 2024, and which countries experienced the strongest and weakest recoveries following the COVID-19 pandemic?

Data Tidying Approach

The original dataset was in wide format, with each year stored in a separate column. I used pivot_longer() from the tidyr package to convert the year columns into two variables: Year and LifeExpectancy.

I also used dplyr to select the relevant columns, check missing values, and remove regional aggregates using World Bank country metadata. I kept the original CSV files unchanged and completed all transformations in R.

Analysis Approach

I compared life expectancy in 2019, 2021, and 2024 to examine changes during and after the pandemic. I calculated the changes for individual countries and economies and compared patterns across income groups.

I also created line charts to show life expectancy trends and bar charts to highlight countries with the largest declines and strongest recoveries.

Data Challenges

One challenge was separating individual countries and economies from regional aggregates. Some observations also had missing values or unusual year-to-year changes that required further attention.

Another important consideration was that changes in life expectancy could not automatically be attributed entirely to COVID-19, since other factors may have influenced the results.

Project Outcome

The analysis included 217 countries and economies from the World Bank dataset. It identified countries with major life expectancy declines, countries with strong recoveries, and places that remained below their 2019 levels in 2024.

The project also demonstrated how data cleaning, reshaping, joining datasets, and visualization in R can help answer real-world research questions.

Data Preparation and Exploration

Load Required Packages

library(tidyverse)
library(knitr)
library(plotly)
library(countrycode)

Import the Original Dataset

life_raw <- read_csv(
  "data/life_expectancy_wide.csv",
  skip = 4,
  show_col_types = FALSE
)
## New names:
## • `` -> `...71`
dim(life_raw)
## [1] 265  71
names(life_raw)
##  [1] "Country Name"   "Country Code"   "Indicator Name" "Indicator Code"
##  [5] "1960"           "1961"           "1962"           "1963"          
##  [9] "1964"           "1965"           "1966"           "1967"          
## [13] "1968"           "1969"           "1970"           "1971"          
## [17] "1972"           "1973"           "1974"           "1975"          
## [21] "1976"           "1977"           "1978"           "1979"          
## [25] "1980"           "1981"           "1982"           "1983"          
## [29] "1984"           "1985"           "1986"           "1987"          
## [33] "1988"           "1989"           "1990"           "1991"          
## [37] "1992"           "1993"           "1994"           "1995"          
## [41] "1996"           "1997"           "1998"           "1999"          
## [45] "2000"           "2001"           "2002"           "2003"          
## [49] "2004"           "2005"           "2006"           "2007"          
## [53] "2008"           "2009"           "2010"           "2011"          
## [57] "2012"           "2013"           "2014"           "2015"          
## [61] "2016"           "2017"           "2018"           "2019"          
## [65] "2020"           "2021"           "2022"           "2023"          
## [69] "2024"           "2025"           "...71"
head(life_raw)
## # A tibble: 6 × 71
##   `Country Name`  `Country Code` `Indicator Name` `Indicator Code` `1960` `1961`
##   <chr>           <chr>          <chr>            <chr>             <dbl>  <dbl>
## 1 Aruba           ABW            Life expectancy… SP.DYN.LE00.IN     64.0   64.2
## 2 Africa Eastern… AFE            Life expectancy… SP.DYN.LE00.IN     44.2   44.5
## 3 Afghanistan     AFG            Life expectancy… SP.DYN.LE00.IN     32.8   33.3
## 4 Africa Western… AFW            Life expectancy… SP.DYN.LE00.IN     37.8   38.1
## 5 Angola          AGO            Life expectancy… SP.DYN.LE00.IN     37.9   36.9
## 6 Albania         ALB            Life expectancy… SP.DYN.LE00.IN     56.4   57.5
## # ℹ 65 more variables: `1962` <dbl>, `1963` <dbl>, `1964` <dbl>, `1965` <dbl>,
## #   `1966` <dbl>, `1967` <dbl>, `1968` <dbl>, `1969` <dbl>, `1970` <dbl>,
## #   `1971` <dbl>, `1972` <dbl>, `1973` <dbl>, `1974` <dbl>, `1975` <dbl>,
## #   `1976` <dbl>, `1977` <dbl>, `1978` <dbl>, `1979` <dbl>, `1980` <dbl>,
## #   `1981` <dbl>, `1982` <dbl>, `1983` <dbl>, `1984` <dbl>, `1985` <dbl>,
## #   `1986` <dbl>, `1987` <dbl>, `1988` <dbl>, `1989` <dbl>, `1990` <dbl>,
## #   `1991` <dbl>, `1992` <dbl>, `1993` <dbl>, `1994` <dbl>, `1995` <dbl>, …

Inspect the Original Data Structure

The original World Bank dataset uses a wide format, where each row represents a country or regional aggregate and each year is stored in a separate column.

life_raw %>%
  select(
    `Country Name`,
    `Country Code`,
    `2019`:`2024`
  ) %>%
  glimpse()
## Rows: 265
## Columns: 8
## $ `Country Name` <chr> "Aruba", "Africa Eastern and Southern", "Afghanistan", …
## $ `Country Code` <chr> "ABW", "AFE", "AFG", "AFW", "AGO", "ALB", "AND", "ARB",…
## $ `2019`         <dbl> 76.01900, 63.85726, 62.94100, 57.14283, 63.05100, 79.46…
## $ `2020`         <dbl> 75.40600, 63.76648, 61.45400, 57.35771, 63.11600, 77.82…
## $ `2021`         <dbl> 73.65500, 62.98000, 60.41700, 57.35502, 62.95800, 76.84…
## $ `2022`         <dbl> 76.22600, 64.48715, 65.61700, 57.97900, 64.24600, 78.76…
## $ `2023`         <dbl> 76.35300, 65.14623, 66.03500, 58.84748, 64.61700, 79.60…
## $ `2024`         <dbl> 76.50000, 65.34993, 66.28900, 59.04154, 64.80500, 79.77…
life_raw %>%
  select(
    `Country Name`,
    `Country Code`,
    `2019`,
    `2020`,
    `2021`,
    `2022`,
    `2023`,
    `2024`
  ) %>%
  head(10) %>%
  kable(
    caption = "Original Wide-Format Life Expectancy Data"
  )
Original Wide-Format Life Expectancy Data
Country Name Country Code 2019 2020 2021 2022 2023 2024
Aruba ABW 76.01900 75.40600 73.65500 76.22600 76.35300 76.50000
Africa Eastern and Southern AFE 63.85726 63.76648 62.98000 64.48715 65.14623 65.34993
Afghanistan AFG 62.94100 61.45400 60.41700 65.61700 66.03500 66.28900
Africa Western and Central AFW 57.14283 57.35771 57.35502 57.97900 58.84748 59.04154
Angola AGO 63.05100 63.11600 62.95800 64.24600 64.61700 64.80500
Albania ALB 79.46700 77.82400 76.84400 78.76900 79.60200 79.77600
Andorra AND 84.09800 79.41800 82.33100 84.01600 84.04100 84.18800
Arab World ARB 71.83989 70.72656 70.40411 71.87610 72.44468 72.72181
United Arab Emirates ARE 82.59600 81.93600 79.08300 80.48700 82.90900 83.06900
Argentina ARG 76.84700 75.87800 73.94800 75.80600 77.39500 77.54300

Data Tidying: Wide to Long Format

The original World Bank dataset contained a separate column for each year. I used pivot_longer() to transform these columns into a single Year variable and a single LifeExpectancy variable.

Since my research focused on changes between 2019 and 2024, I selected those years for the analysis.

life_tidy <- life_raw %>%
  select(
    `Country Name`,
    `Country Code`,
    `2019`:`2024`
  ) %>%
  pivot_longer(
    cols = `2019`:`2024`,
    names_to = "Year",
    values_to = "LifeExpectancy"
  ) %>%
  mutate(
    Year = as.integer(Year)
  )

head(life_tidy, 12)
## # A tibble: 12 × 4
##    `Country Name`              `Country Code`  Year LifeExpectancy
##    <chr>                       <chr>          <int>          <dbl>
##  1 Aruba                       ABW             2019           76.0
##  2 Aruba                       ABW             2020           75.4
##  3 Aruba                       ABW             2021           73.7
##  4 Aruba                       ABW             2022           76.2
##  5 Aruba                       ABW             2023           76.4
##  6 Aruba                       ABW             2024           76.5
##  7 Africa Eastern and Southern AFE             2019           63.9
##  8 Africa Eastern and Southern AFE             2020           63.8
##  9 Africa Eastern and Southern AFE             2021           63.0
## 10 Africa Eastern and Southern AFE             2022           64.5
## 11 Africa Eastern and Southern AFE             2023           65.1
## 12 Africa Eastern and Southern AFE             2024           65.3

Inspect the Tidied Dataset

cat("Original dataset dimensions:\n")
## Original dataset dimensions:
dim(life_raw)
## [1] 265  71
cat("\nTidied dataset dimensions:\n")
## 
## Tidied dataset dimensions:
dim(life_tidy)
## [1] 1590    4
cat("\nTidied dataset structure:\n")
## 
## Tidied dataset structure:
glimpse(life_tidy)
## Rows: 1,590
## Columns: 4
## $ `Country Name` <chr> "Aruba", "Aruba", "Aruba", "Aruba", "Aruba", "Aruba", "…
## $ `Country Code` <chr> "ABW", "ABW", "ABW", "ABW", "ABW", "ABW", "AFE", "AFE",…
## $ Year           <int> 2019, 2020, 2021, 2022, 2023, 2024, 2019, 2020, 2021, 2…
## $ LifeExpectancy <dbl> 76.01900, 75.40600, 73.65500, 76.22600, 76.35300, 76.50…

Display the Tidied Data

life_tidy %>%
  head(12) %>%
  kable(
    digits = 2,
    caption = "Life Expectancy Data After Tidying"
  )
Life Expectancy Data After Tidying
Country Name Country Code Year LifeExpectancy
Aruba ABW 2019 76.02
Aruba ABW 2020 75.41
Aruba ABW 2021 73.66
Aruba ABW 2022 76.23
Aruba ABW 2023 76.35
Aruba ABW 2024 76.50
Africa Eastern and Southern AFE 2019 63.86
Africa Eastern and Southern AFE 2020 63.77
Africa Eastern and Southern AFE 2021 62.98
Africa Eastern and Southern AFE 2022 64.49
Africa Eastern and Southern AFE 2023 65.15
Africa Eastern and Southern AFE 2024 65.35

Country Metadata and Data Cleaning

The World Bank dataset included both individual countries and regional aggregates. I used the country metadata file to identify countries and economies and add regional and income-group information.

Import Country Metadata

country_metadata_raw <- read_csv(
  "data/life_expectancy_countries.csv",
  show_col_types = FALSE
)
## New names:
## • `` -> `...6`
dim(country_metadata_raw)
## [1] 264   6
names(country_metadata_raw)
## [1] "Country Code" "Region"       "IncomeGroup"  "SpecialNotes" "TableName"   
## [6] "...6"
country_metadata_raw %>%
  head(10) %>%
  kable(caption = "World Bank Country Metadata")
World Bank Country Metadata
Country Code Region IncomeGroup SpecialNotes TableName …6
ABW Latin America & Caribbean High income NA Aruba NA
AFE NA NA 26 countries, stretching from the Red Sea in the North to the Cape of Good Hope in the South (https://www.worldbank.org/en/region/afr/eastern-and-southern-africa) Africa Eastern and Southern NA
AFG Middle East & North Africa Low income The reporting period for national accounts data is designated as either calendar year basis (CY) or fiscal year basis (FY). For this country, it is fiscal year-based (fiscal year-end: March 20). Also, an estimate (PA.NUS.ATLS) of the exchange rate covers the same period and thus differs from the official exchange rate (CY).

In addition, the World Bank systematically assesses the appropriateness of official exchange rates as conversion factors. In this country, multiple or dual exchange rate activity exists and must be accounted for appropriately in underlying statistics. An alternative estimate (“alternative conversion factor” - PA.NUS.ATLS) is thus calculated as a weighted average of the different exchange rates in use in the country. Doing so better reflects economic reality and leads to more accurate cross-country comparisons and country classifications by income level. For this country, this applies to the period 1960-2006. Alternative conversion factors are used in the Atlas methodology and elsewhere in World Development Indicators as single-year conversion factors. |Afghanistan |NA | |AFW |NA |NA |22 countries, stretching from the westernmost point of Africa, across the equator, and partly along the Atlantic Ocean till the Republic of Congo in the South (https://www.worldbank.org/en/region/afr/western-and-central-africa) |Africa Western and Central |NA | |AGO |Sub-Saharan Africa |Lower middle income |The World Bank systematically assesses the appropriateness of official exchange rates as conversion factors. In this country, multiple or dual exchange rate activity exists and must be accounted for appropriately in underlying statistics. An alternative estimate (“alternative conversion factor” - PA.NUS.ATLS) is thus calculated as a weighted average of the different exchange rates in use in the country. Doing so better reflects economic reality and leads to more accurate cross-country comparisons and country classifications by income level. For this country, this applies to the period 1994-2025. Alternative conversion factors are used in the Atlas methodology and elsewhere in World Development Indicators as single-year conversion factors. |Angola |NA | |ALB |Europe & Central Asia |Upper middle income |NA |Albania |NA | |AND |Europe & Central Asia |High income |NA |Andorra |NA | |ARB |NA |NA |Arab World aggregate. Arab World is composed of members of the League of Arab States. |Arab World |NA | |ARE |Middle East & North Africa |High income |NA |United Arab Emirates |NA | |ARG |Latin America & Caribbean |Upper middle income |Due to the limitations of the Atlas method in classifying countries experiencing persistent high inflation, this economy remains classified as upper-middle-income. The World Bank systematically assesses the appropriateness of official exchange rates as conversion factors. In this country, multiple or dual exchange rate activity exists and must be accounted for appropriately in underlying statistics. An alternative estimate (“alternative conversion factor” - PA.NUS.ATLS) is thus calculated as a weighted average of the different exchange rates in use in the country. Doing so better reflects economic reality and leads to more accurate cross-country comparisons and country classifications by income level. For this country, this applies to the period 1971-2018. Alternative conversion factors are used in the Atlas methodology and elsewhere in World Development Indicators as single-year conversion factors. |Argentina |NA |

Inspect Metadata Structure

glimpse(country_metadata_raw)
## Rows: 264
## Columns: 6
## $ `Country Code` <chr> "ABW", "AFE", "AFG", "AFW", "AGO", "ALB", "AND", "ARB",…
## $ Region         <chr> "Latin America & Caribbean", NA, "Middle East & North A…
## $ IncomeGroup    <chr> "High income", NA, "Low income", NA, "Lower middle inco…
## $ SpecialNotes   <chr> NA, "26 countries, stretching from the Red Sea in the N…
## $ TableName      <chr> "Aruba", "Africa Eastern and Southern", "Afghanistan", …
## $ ...6           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…

Joining and Cleaning the Data

I joined the tidied life expectancy dataset with the World Bank country metadata using Country Code.

I then removed regional aggregates by keeping records with valid region and income-group classifications.

Prepare Country Metadata

country_metadata <- country_metadata_raw %>%
  select(
    `Country Code`,
    Region,
    IncomeGroup
  ) %>%
  distinct(`Country Code`, .keep_all = TRUE)

country_metadata %>%
  head(10) %>%
  kable(caption = "Cleaned Country Metadata")
Cleaned Country Metadata
Country Code Region IncomeGroup
ABW Latin America & Caribbean High income
AFE NA NA
AFG Middle East & North Africa Low income
AFW NA NA
AGO Sub-Saharan Africa Lower middle income
ALB Europe & Central Asia Upper middle income
AND Europe & Central Asia High income
ARB NA NA
ARE Middle East & North Africa High income
ARG Latin America & Caribbean Upper middle income

Join Life Expectancy and Country Metadata

life_joined <- life_tidy %>%
  left_join(
    country_metadata,
    by = "Country Code"
  )

cat("Rows after joining:", nrow(life_joined), "\n")
## Rows after joining: 1590
life_joined %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "Life Expectancy Data with Country Metadata"
  )
Life Expectancy Data with Country Metadata
Country Name Country Code Year LifeExpectancy Region IncomeGroup
Aruba ABW 2019 76.02 Latin America & Caribbean High income
Aruba ABW 2020 75.41 Latin America & Caribbean High income
Aruba ABW 2021 73.66 Latin America & Caribbean High income
Aruba ABW 2022 76.23 Latin America & Caribbean High income
Aruba ABW 2023 76.35 Latin America & Caribbean High income
Aruba ABW 2024 76.50 Latin America & Caribbean High income
Africa Eastern and Southern AFE 2019 63.86 NA NA
Africa Eastern and Southern AFE 2020 63.77 NA NA
Africa Eastern and Southern AFE 2021 62.98 NA NA
Africa Eastern and Southern AFE 2022 64.49 NA NA

Remove Regional Aggregates

life_clean <- life_joined %>%
  filter(
    !is.na(Region),
    !is.na(IncomeGroup)
  )

cat("Rows before filtering:", nrow(life_joined), "\n")
## Rows before filtering: 1590
cat("Rows after filtering:", nrow(life_clean), "\n")
## Rows after filtering: 1302
cat(
  "Number of countries:",
  n_distinct(life_clean$`Country Code`),
  "\n"
)
## Number of countries: 217
life_clean %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "Cleaned Country-Level Life Expectancy Data"
  )
Cleaned Country-Level Life Expectancy Data
Country Name Country Code Year LifeExpectancy Region IncomeGroup
Aruba ABW 2019 76.02 Latin America & Caribbean High income
Aruba ABW 2020 75.41 Latin America & Caribbean High income
Aruba ABW 2021 73.66 Latin America & Caribbean High income
Aruba ABW 2022 76.23 Latin America & Caribbean High income
Aruba ABW 2023 76.35 Latin America & Caribbean High income
Aruba ABW 2024 76.50 Latin America & Caribbean High income
Afghanistan AFG 2019 62.94 Middle East & North Africa Low income
Afghanistan AFG 2020 61.45 Middle East & North Africa Low income
Afghanistan AFG 2021 60.42 Middle East & North Africa Low income
Afghanistan AFG 2022 65.62 Middle East & North Africa Low income

Check Missing Values

missing_summary <- life_clean %>%
  group_by(Year) %>%
  summarise(
    TotalRecords = n(),
    MissingLifeExpectancy = sum(is.na(LifeExpectancy)),
    AvailableLifeExpectancy = sum(!is.na(LifeExpectancy)),
    .groups = "drop"
  )

missing_summary %>%
  kable(
    caption = "Missing Life Expectancy Values by Year"
  )
Missing Life Expectancy Values by Year
Year TotalRecords MissingLifeExpectancy AvailableLifeExpectancy
2019 217 0 217
2020 217 0 217
2021 217 0 217
2022 217 0 217
2023 217 0 217
2024 217 0 217

Life Expectancy Decline and Recovery Analysis

To understand how life expectancy changed during and after the COVID-19 pandemic, I compared life expectancy in 2019, 2021, and 2024.

The analysis measured changes during the pandemic period, recovery after 2021, and the overall difference from the pre-pandemic baseline.

Prepare Country-Level Comparisons

life_changes <- life_clean %>%
  filter(Year %in% c(2019, 2021, 2024)) %>%
  select(
    `Country Name`,
    `Country Code`,
    Region,
    IncomeGroup,
    Year,
    LifeExpectancy
  ) %>%
  pivot_wider(
    names_from = Year,
    values_from = LifeExpectancy,
    names_prefix = "Life_"
  ) %>%
  mutate(
    PandemicChange = Life_2021 - Life_2019,
    RecoveryChange = Life_2024 - Life_2021,
    OverallChange = Life_2024 - Life_2019
  )

life_changes %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "Life Expectancy Changes by Country"
  )
Life Expectancy Changes by Country
Country Name Country Code Region IncomeGroup Life_2019 Life_2021 Life_2024 PandemicChange RecoveryChange OverallChange
Aruba ABW Latin America & Caribbean High income 76.02 73.66 76.50 -2.36 2.84 0.48
Afghanistan AFG Middle East & North Africa Low income 62.94 60.42 66.29 -2.52 5.87 3.35
Angola AGO Sub-Saharan Africa Lower middle income 63.05 62.96 64.81 -0.09 1.85 1.75
Albania ALB Europe & Central Asia Upper middle income 79.47 76.84 79.78 -2.62 2.93 0.31
Andorra AND Europe & Central Asia High income 84.10 82.33 84.19 -1.77 1.86 0.09
United Arab Emirates ARE Middle East & North Africa High income 82.60 79.08 83.07 -3.51 3.99 0.47
Argentina ARG Latin America & Caribbean Upper middle income 76.85 73.95 77.54 -2.90 3.60 0.70
Armenia ARM Europe & Central Asia Upper middle income 76.22 72.28 78.32 -3.94 6.04 2.10
American Samoa ASM East Asia & Pacific High income 72.75 72.71 72.99 -0.04 0.28 0.24
Antigua and Barbuda ATG Latin America & Caribbean High income 77.17 77.20 77.77 0.03 0.57 0.60

Check Available Comparisons

life_changes %>%
  summarise(
    TotalCountries = n(),
    CompleteComparisons = sum(
      !is.na(Life_2019) &
      !is.na(Life_2021) &
      !is.na(Life_2024)
    ),
    MissingComparisons = sum(
      is.na(Life_2019) |
      is.na(Life_2021) |
      is.na(Life_2024)
    )
  ) %>%
  kable(
    caption = "Data Availability for Country Comparisons"
  )
Data Availability for Country Comparisons
TotalCountries CompleteComparisons MissingComparisons
217 217 0

Countries with the Largest Declines

life_changes %>%
  filter(!is.na(PandemicChange)) %>%
  arrange(PandemicChange) %>%
  select(
    `Country Name`,
    Region,
    PandemicChange
  ) %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "10 Largest Life Expectancy Declines, 2019–2021"
  )
10 Largest Life Expectancy Declines, 2019–2021
Country Name Region PandemicChange
Bolivia Latin America & Caribbean -6.39
Paraguay Latin America & Caribbean -5.56
Mexico Latin America & Caribbean -4.78
Guyana Latin America & Caribbean -4.74
Peru Latin America & Caribbean -4.68
Lebanon Middle East & North Africa -4.56
Ecuador Latin America & Caribbean -4.54
Cuba Latin America & Caribbean -4.21
Colombia Latin America & Caribbean -4.10
South Africa Sub-Saharan Africa -4.06

Countries with the Strongest Recoveries

life_changes %>%
  filter(!is.na(RecoveryChange)) %>%
  arrange(desc(RecoveryChange)) %>%
  select(
    `Country Name`,
    Region,
    RecoveryChange
  ) %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "10 Largest Life Expectancy Increases, 2021–2024"
  )
10 Largest Life Expectancy Increases, 2021–2024
Country Name Region RecoveryChange
Central African Republic Sub-Saharan Africa 17.39
Bolivia Latin America & Caribbean 7.31
Namibia Sub-Saharan Africa 6.67
Peru Latin America & Caribbean 6.34
Armenia Europe & Central Asia 6.04
Eswatini Sub-Saharan Africa 6.04
Guyana Latin America & Caribbean 6.00
Botswana Sub-Saharan Africa 5.99
Paraguay Latin America & Caribbean 5.87
Afghanistan Middle East & North Africa 5.87

Countries Still Below Their 2019 Levels

life_changes %>%
  filter(!is.na(OverallChange), OverallChange < 0) %>%
  arrange(OverallChange) %>%
  select(
    `Country Name`,
    Region,
    OverallChange
  ) %>%
  head(10) %>%
  kable(
    digits = 2,
    caption = "Countries Furthest Below 2019 Life Expectancy in 2024"
  )
Countries Furthest Below 2019 Life Expectancy in 2024
Country Name Region OverallChange
West Bank and Gaza Middle East & North Africa -6.60
Libya Middle East & North Africa -1.82
Greenland Europe & Central Asia -1.14
Thailand East Asia & Pacific -0.63
Macao SAR, China East Asia & Pacific -0.60
Germany Europe & Central Asia -0.50
Mauritius Sub-Saharan Africa -0.45
Qatar Middle East & North Africa -0.42
South Sudan Sub-Saharan Africa -0.39
Iceland Europe & Central Asia -0.35

Data Visualization

Largest Life Expectancy Declines

largest_declines <- life_changes %>%
  filter(!is.na(PandemicChange)) %>%
  slice_min(
    PandemicChange,
    n = 10,
    with_ties = FALSE
  )

ggplot(
  largest_declines,
  aes(
    x = reorder(`Country Name`, PandemicChange),
    y = PandemicChange
  )
) +
  geom_col(fill = "#C44E52") +
  coord_flip() +
  labs(
    title = "Countries with the Largest Life Expectancy Declines",
    subtitle = "Change from 2019 to 2021",
    x = "Country",
    y = "Change in Life Expectancy (Years)",
    caption = "Source: World Bank World Development Indicators"
  ) +
  theme_minimal()

This visualization shows the 10 countries with the largest life expectancy declines between 2019 and 2021. Bolivia experienced the largest decline at approximately 6.39 years, followed by Paraguay at 5.56 years and Mexico at 4.78 years. Several Latin American countries appear in this chart, showing how strongly life expectancy was affected in parts of the region during the pandemic period.

Strongest Life Expectancy Recoveries

strongest_recoveries <- life_changes %>%
  filter(!is.na(RecoveryChange)) %>%
  slice_max(
    RecoveryChange,
    n = 10,
    with_ties = FALSE
  )

ggplot(
  strongest_recoveries,
  aes(
    x = reorder(`Country Name`, RecoveryChange),
    y = RecoveryChange
  )
) +
  geom_col(fill = "#4C9F70") +
  coord_flip() +
  labs(
    title = "Countries with the Strongest Life Expectancy Recoveries",
    subtitle = "Change from 2021 to 2024",
    x = "Country",
    y = "Increase in Life Expectancy (Years)",
    caption = "Source: World Bank World Development Indicators"
  ) +
  theme_minimal()

This visualization shows the countries with the largest increases in life expectancy between 2021 and 2024. The Central African Republic had the largest reported increase at 17.4 years, but its data contain unusual fluctuations that require verification. Bolivia followed with an increase of 7.31 years, Namibia with 6.67 years, and Peru with 6.34 years. The results show that countries recovered at different rates, and a strong recovery did not always mean returning to pre-pandemic levels.

Data Quality Check: Central African Republic

The Central African Republic has unusually large changes in life expectancy between consecutive years. I reviewed these observations separately because they may influence the ranking of countries with the strongest recoveries.

life_clean %>%
  filter(`Country Code` == "CAF") %>%
  arrange(Year) %>%
  select(Year, LifeExpectancy) %>%
  kable(
    digits = 2,
    caption = "Central African Republic Life Expectancy, 2019–2024"
  )
Central African Republic Life Expectancy, 2019–2024
Year LifeExpectancy
2019 31.53
2020 50.60
2021 40.28
2022 18.82
2023 57.41
2024 57.67

These unusually large changes, especially the decrease in 2022 followed by a sharp increase in 2023, suggest that this country’s results should be interpreted cautiously until the source data can be verified.

Interactive World Life Expectancy Recovery Map

This interactive map shows how life expectancy changed across countries between 2019 and 2024 compared with their 2019 levels. Use the year slider to explore changes over time.

map_data <- life_clean %>%
  group_by(`Country Code`) %>%
  mutate(
    Life2019 = LifeExpectancy[match(2019, Year)],
    ChangeFrom2019 = LifeExpectancy - Life2019
  ) %>%
  ungroup() %>%
  filter(
    !is.na(ChangeFrom2019),
    !is.na(LifeExpectancy)
  ) %>%
  mutate(
    HoverText = paste0(
      "<b>", `Country Name`, "</b>",
      "<br>Year: ", Year,
      "<br>Life Expectancy: ",
      round(LifeExpectancy, 2), " years",
      "<br>Change from 2019: ",
      sprintf("%+.2f", ChangeFrom2019), " years"
    )
  )

plot_ly(
  data = map_data,
  type = "choropleth",
  locations = ~`Country Code`,
  locationmode = "ISO-3",
  z = ~ChangeFrom2019,
  frame = ~Year,
  text = ~HoverText,
  hoverinfo = "text",
  colorscale = list(
    c(0, "#C44E52"),
    c(0.5, "#F7F7F7"),
    c(1, "#4C9F70")
  ),
  zmin = -10,
  zmax = 10,
  zmid = 0,
  colorbar = list(title = "Change (Years)")
) %>%
  layout(
    title = "Global Life Expectancy Change Since 2019",
    geo = list(
      showframe = FALSE,
      showcoastlines = TRUE,
      projection = list(type = "natural earth")
    )
  ) %>%
  animation_opts(
    frame = 1000,
    transition = 500,
    redraw = TRUE
  ) %>%
  animation_slider(
    currentvalue = list(prefix = "Year: ")
  )

The interactive map uses red to represent countries with lower life expectancy than in 2019 and green for countries with higher life expectancy. Viewers can move the year slider to compare different years and hover over countries to see their values. Countries without available data or a matching map location may not be colored.

Results and Discussion

Countries Still Below Their 2019 Levels

Although many countries experienced increases in life expectancy after 2021, some had not returned to their 2019 levels by 2024. West Bank and Gaza showed the largest overall decline at approximately 6.60 years, followed by Libya and Greenland. This shows that recovery was not equal across countries.

Limitations

Some countries have missing data or unusual changes that require verification. The dataset also includes territories and economies, not just independent countries. Additionally, changes in life expectancy cannot be attributed entirely to COVID-19 because other factors may have influenced the results. Countries with missing life expectancy values were excluded from comparisons requiring those years, so the rankings only include countries with available data.

Conclusion

This project analyzed life expectancy across 217 countries and economies from 2019 to 2024 using World Bank data. The results show that many countries experienced declines during the pandemic period and recovered afterward, but not at the same rate. By cleaning, transforming, and visualizing the data in R, I was able to identify differences in life expectancy recovery across countries and income groups.