Project 1:Life Expectancy vs. Health Expenditure

Introduction

The Life Expectancy vs. Health Expenditure dataset from Our World in Data compares life expectancy and health expenditure per capita across countries and over time. This dataset combines data from different sources, including the United Nations’ World Population Prospects (2024) and the Organisation for Economic Co-operation and Development (OECD, 2026).

The dataset is available through Our World in Data. I have linked the source here.

The dataset contains six main variables, including three categorical variables and three quantitative variables. These variables provide information about different countries, their life expectancy, and their healthcare spending over time. The main variables are described below:

  • Entity: The name of the country or territory for which the data was collected, such as Albania, France, or the United States.

  • Code: The three-letter country code used to identify each country, such as ALB for Albania, FRA for France, and USA for the United States.

  • Year: The year in which the data was recorded, allowing comparisons across different years.

  • Life expectancy: The average number of years a person is expected to live, based on the mortality patterns used in the data.

  • Health expenditure per capita: The amount spent on healthcare per person in a country, expressed in monetary terms.

  • World region according to OWID: The name of the world region or continent to which the country belongs.

Objective

The goal of my research is to explore the relationship between the life expectancy variable and the health expenditure per capital one. I will examine whether countries that spend more on healthcare per person tend to have higher life expectancy and how this relationship varies across countries and over time.

Uploading libraries and dataset

library(tidyverse) 
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2) 
library(dplyr) 
library(readr)
df<- read_csv('lf vs he.csv') 
Rows: 18809 Columns: 6
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Entity, Code, World region according to OWID
dbl (3): Year, Life expectancy, Health expenditure per capita

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(df)
# A tibble: 6 × 6
  Entity      Code   Year `Life expectancy` `Health expenditure per capita`
  <chr>       <chr> <dbl>             <dbl>                           <dbl>
1 Afghanistan AFG    1950              28.2                              NA
2 Afghanistan AFG    1951              28.6                              NA
3 Afghanistan AFG    1952              29.0                              NA
4 Afghanistan AFG    1953              29.5                              NA
5 Afghanistan AFG    1954              29.7                              NA
6 Afghanistan AFG    1955              30.4                              NA
# ℹ 1 more variable: `World region according to OWID` <chr>
str(df)
spc_tbl_ [18,809 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Entity                        : chr [1:18809] "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ Code                          : chr [1:18809] "AFG" "AFG" "AFG" "AFG" ...
 $ Year                          : num [1:18809] 1950 1951 1952 1953 1954 ...
 $ Life expectancy               : num [1:18809] 28.2 28.6 29 29.5 29.7 ...
 $ Health expenditure per capita : num [1:18809] NA NA NA NA NA NA NA NA NA NA ...
 $ World region according to OWID: chr [1:18809] "Asia" "Asia" "Asia" "Asia" ...
 - attr(*, "spec")=
  .. cols(
  ..   Entity = col_character(),
  ..   Code = col_character(),
  ..   Year = col_double(),
  ..   `Life expectancy` = col_double(),
  ..   `Health expenditure per capita` = col_double(),
  ..   `World region according to OWID` = col_character()
  .. )
 - attr(*, "problems")=<pointer: 0x0000026b900f4660> 

Cleaning the dataset

colSums(is.na(df))
                        Entity                           Code 
                             0                            370 
                          Year                Life expectancy 
                             0                             87 
 Health expenditure per capita World region according to OWID 
                         16675                           1184 
df1 <- df %>% filter(!is.na(`Health expenditure per capita`), !is.na(`World region according to OWID`), !is.na(`Life expectancy`))  
df1<- df1 %>% rename('Region'='World region according to OWID')
colSums(is.na(df1))
                       Entity                          Code 
                            0                             0 
                         Year               Life expectancy 
                            0                             0 
Health expenditure per capita                        Region 
                            0                             0 

Plot 1: Health expenditure over the years ~ Line plot

yearly_health <- df1 %>%
  group_by(Year) %>%
  summarise(
    mean_expenditure = mean(
      `Health expenditure per capita`))

ggplot(yearly_health,
       aes(x = Year, y = mean_expenditure)) +
  geom_line(linewidth = 1, colour = 'purple') +
  labs(
    title = "Average Health Expenditure Per Capita Over Time",
    x = "Year",
    y = "Average health expenditure per capita",
    caption = "Source: Our World in Data"
  ) +
  theme_minimal()

Plot 2:Life expectancy vs Health expenditure per capital ~ Scatterplot

ggplot(df1, aes(x=`Health expenditure per capita`, y= `Life expectancy` )) +  
  labs(title = "Life expectancy vs Health expenditure per capital",   
  caption = "Source: UN, World Population Prospects (2024); OECD (2026)",   
  x="Health expenditure per capita (log scale)",   
  y="Life expectancy") + 
  geom_point(aes(color = Region), alpha = 0.4, size = 0.75) +
  ylim(50,85) +
  geom_smooth(method='lm',formula=y~x, colour = 'purple', size = 0.75) +
scale_x_log10() +
  theme_minimal() +
theme(legend.position = "right")
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.

Linear regression model

Examining which variable has the strongest correlation with Life expectancy:

library(DataExplorer)
plot_correlation(df1)
2 features with more than 20 categories ignored!
Entity: 59 categories
Code: 59 categories

Life expectancy and Health expenditure per capita have the greatest correlation value: r= 0.67

Model analysing the relationship between Life expectancy and Health expenditure per capita

model1 <- lm(`Life expectancy`~ `Health expenditure per capita`, data = df1)
summary(model1)

Call:
lm(formula = `Life expectancy` ~ `Health expenditure per capita`, 
    data = df1)

Residuals:
     Min       1Q   Median       3Q      Max 
-19.5789  -1.4334   0.1653   2.0127   6.3240 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     7.215e+01  1.262e-01  571.79   <2e-16 ***
`Health expenditure per capita` 1.604e-03  3.898e-05   41.14   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.253 on 2045 degrees of freedom
Multiple R-squared:  0.4529,    Adjusted R-squared:  0.4526 
F-statistic:  1693 on 1 and 2045 DF,  p-value: < 2.2e-16

Equation:

Linear regression diagnostic plots for the model

# Divide the plotting window into 2 rows and 2 columns
# so that we can display 4 graphs at the same time
par(mfrow = c(2, 2))

# Display 4 diagnodtic plots to evaluate the linear regression model
plot(model1)

Conclusion

Cleaning explanation

The data-cleaning process was relatively straightforward. I started with identifying the missing value (N/A) in my dataset, using ColSums(is.na()). Then I filtered the dataset to exclude all the missing value with “!is.na” and renamed the column “World region according to OWID”: “Region”, to make it easier to access. Finally, I used ColSums(is.na()) again to check if there wasn’t any remaining missing values.

Visualizations explanation and interpretation

The first plot illustrates the change in average health expenditure per capita over time. I created this plot using geom_line with the x-axis representing the year and the y-axis representing the average health expenditure per capita. The plot shows that health expenditure per capita kept increasing over the years.

The second plot is a scatterplot titled: Life expectancy vs Health expenditure per capital. I created this scatterplot using geom_point combined with geom_smooth. Each point represent a country-year observation, with the x-axis representing the Health expenditure per capita, and the y-axis representing the Life expectancy. I also used geom_smooth() to add a trend line to the plot, making it easier to visualize the overall relationship between health expenditure per capita and life expectancy. This scatterplot shows a positive relationship between health expenditure per capita and life expectancy, suggesting that countries that spend the most on healthcare per person tend to have higher life expectancy.

Linear regression model interpretation

After examining the correlation between the variables using plot_correlation(), I found that Life expectancy and Health expenditure per capita had the strongest correlation among the quantitative variables, with a correlation value of approximately 0.67. This indicates a moderately strong positive relationship between the two variables. Therefore, I decided to use them to create a simple linear regression model to further investigate this relationship.

The regression model shows a positive relationship between health expenditure per capita and life expectancy. The regression equation is:

Life expectancy = 72.15 + 0.001604 × Health expenditure per capita

The slope coefficient (0.001604) indicates that, on average, a one-unit increase in health expenditure per capita is associated with an increase of approximately 0.001604 years in life expectancy. The intercept (72.15) represents the predicted life expectancy when health expenditure per capita is zero.

The p-value for health expenditure per capita is less than 0.001, indicating a statistically significant relationship between the two variables. The R-squared value of 0.4529 means that the model explains approximately 45.29% of the variation in life expectancy. This suggests that health expenditure per capita is an important explanatory variable, although other factors may also contribute to differences in life expectancy.

Finally, I used four diagnostic plots to evaluate the assumptions of the linear regression model. These plots help assess the linearity of the relationship, the normality of the residuals, the consistency of the residual variance, and the presence of influential observations.

Obstacles encountered and Solutions

During my analysis, I encountred two obstacles. The first was the large number of missing values in the health expenditure variable. I removed observations with missing values in the variables required for my analysis. Although this allowed me to perform the regression analysis, it substantially reduced the dataset and may have affected how representative the results are.

The second was that the scatterplot was crowded because the dataset contained many observations with the same countries appearing multiple times because data were collected across different years. To address this issue, I decided to use scale_x_ log10(). This helped display the wide range of health expenditure values more clearly. Finally, I manipulated alpha and size to adjust the points appearence.

Resources

https://ourworldindata.org/grapher/life-expectancy-vs-health-expenditure

https://www.geeksforgeeks.org/r-machine-learning/diagnostic-plots-for-model-evaluation/