library(ggplot2)
## Warning: package 'ggplot2' was built under R version 3.6.3
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
## 
##     date
library(readxl)
## Warning: package 'readxl' was built under R version 3.6.2
library(readr)
library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:readr':
## 
##     col_factor
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 3.6.2
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## v tibble  3.0.6     v dplyr   1.0.4
## v tidyr   1.1.2     v stringr 1.4.0
## v purrr   0.3.4     v forcats 0.4.0
## Warning: package 'tibble' was built under R version 3.6.3
## Warning: package 'tidyr' was built under R version 3.6.3
## Warning: package 'purrr' was built under R version 3.6.3
## Warning: package 'dplyr' was built under R version 3.6.3
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x lubridate::as.difftime() masks base::as.difftime()
## x scales::col_factor()     masks readr::col_factor()
## x lubridate::date()        masks base::date()
## x purrr::discard()         masks scales::discard()
## x dplyr::filter()          masks stats::filter()
## x lubridate::intersect()   masks base::intersect()
## x dplyr::lag()             masks stats::lag()
## x lubridate::setdiff()     masks base::setdiff()
## x lubridate::union()       masks base::union()
library(lubridate)
library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(corrplot)
## Warning: package 'corrplot' was built under R version 3.6.3
## corrplot 0.84 loaded
library(ggthemes)
## Warning: package 'ggthemes' was built under R version 3.6.3
library(viridisLite)
## Warning: package 'viridisLite' was built under R version 3.6.3
library(gclus)
## Warning: package 'gclus' was built under R version 3.6.3
## Loading required package: cluster
## Warning: package 'cluster' was built under R version 3.6.3
library(tidymodels)
## Warning: package 'tidymodels' was built under R version 3.6.3
## -- Attaching packages -------------------------------------- tidymodels 0.1.2 --
## v broom     0.7.4      v recipes   0.1.15
## v dials     0.0.9      v rsample   0.0.8 
## v infer     0.5.4      v tune      0.1.2 
## v modeldata 0.1.0      v workflows 0.2.1 
## v parsnip   0.1.5      v yardstick 0.0.7
## Warning: package 'broom' was built under R version 3.6.3
## Warning: package 'dials' was built under R version 3.6.3
## Warning: package 'infer' was built under R version 3.6.3
## Warning: package 'modeldata' was built under R version 3.6.3
## Warning: package 'parsnip' was built under R version 3.6.3
## Warning: package 'recipes' was built under R version 3.6.3
## Warning: package 'rsample' was built under R version 3.6.3
## Warning: package 'tune' was built under R version 3.6.3
## Warning: package 'workflows' was built under R version 3.6.3
## Warning: package 'yardstick' was built under R version 3.6.3
## -- Conflicts ----------------------------------------- tidymodels_conflicts() --
## x purrr::discard()  masks scales::discard()
## x plotly::filter()  masks dplyr::filter(), stats::filter()
## x recipes::fixed()  masks stringr::fixed()
## x dplyr::lag()      masks stats::lag()
## x yardstick::spec() masks readr::spec()
## x recipes::step()   masks stats::step()
df <- read_csv("world-happiness-report-2021.csv")
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   `Country name` = col_character(),
##   `Regional indicator` = col_character()
## )
## See spec(...) for full column specifications.
head(df)
## # A tibble: 6 x 20
##   `Country name` `Regional indic~ `Ladder score` `Standard error~ upperwhisker
##   <chr>          <chr>                     <dbl>            <dbl>        <dbl>
## 1 Finland        Western Europe             7.84            0.032         7.90
## 2 Denmark        Western Europe             7.62            0.035         7.69
## 3 Switzerland    Western Europe             7.57            0.036         7.64
## 4 Iceland        Western Europe             7.55            0.059         7.67
## 5 Netherlands    Western Europe             7.46            0.027         7.52
## 6 Norway         Western Europe             7.39            0.035         7.46
## # ... with 15 more variables: lowerwhisker <dbl>, `Logged GDP per
## #   capita` <dbl>, `Social support` <dbl>, `Healthy life expectancy` <dbl>,
## #   `Freedom to make life choices` <dbl>, Generosity <dbl>, `Perceptions of
## #   corruption` <dbl>, `Ladder score in Dystopia` <dbl>, `Explained by: Log GDP
## #   per capita` <dbl>, `Explained by: Social support` <dbl>, `Explained by:
## #   Healthy life expectancy` <dbl>, `Explained by: Freedom to make life
## #   choices` <dbl>, `Explained by: Generosity` <dbl>, `Explained by:
## #   Perceptions of corruption` <dbl>, `Dystopia + residual` <dbl>

Upload the World Happiness Report 2021 csv file as a dataframe.

print(dim(df))
## [1] 149  20
names(df)
##  [1] "Country name"                              
##  [2] "Regional indicator"                        
##  [3] "Ladder score"                              
##  [4] "Standard error of ladder score"            
##  [5] "upperwhisker"                              
##  [6] "lowerwhisker"                              
##  [7] "Logged GDP per capita"                     
##  [8] "Social support"                            
##  [9] "Healthy life expectancy"                   
## [10] "Freedom to make life choices"              
## [11] "Generosity"                                
## [12] "Perceptions of corruption"                 
## [13] "Ladder score in Dystopia"                  
## [14] "Explained by: Log GDP per capita"          
## [15] "Explained by: Social support"              
## [16] "Explained by: Healthy life expectancy"     
## [17] "Explained by: Freedom to make life choices"
## [18] "Explained by: Generosity"                  
## [19] "Explained by: Perceptions of corruption"   
## [20] "Dystopia + residual"

The World Happiness 2021 dataset has 149 rows and 20 columns. The “Ladder score” represents Happiness score. Among the columns, it has the Country name, Regional indicator are in character/string data type. The other variables are in Numerical data type. The “Ladder score in Dystopia” has the same value 2.43 for all rows, therefore, this variable can be ignored as it offers no value for the analysis.

sum(is.na(df))
## [1] 0

There is no NaN values in the dataset.

summary(df)
##  Country name       Regional indicator  Ladder score  
##  Length:149         Length:149         Min.   :2.523  
##  Class :character   Class :character   1st Qu.:4.852  
##  Mode  :character   Mode  :character   Median :5.534  
##                                        Mean   :5.533  
##                                        3rd Qu.:6.255  
##                                        Max.   :7.842  
##  Standard error of ladder score  upperwhisker    lowerwhisker  
##  Min.   :0.02600                Min.   :2.596   Min.   :2.449  
##  1st Qu.:0.04300                1st Qu.:4.991   1st Qu.:4.706  
##  Median :0.05400                Median :5.625   Median :5.413  
##  Mean   :0.05875                Mean   :5.648   Mean   :5.418  
##  3rd Qu.:0.07000                3rd Qu.:6.344   3rd Qu.:6.128  
##  Max.   :0.17300                Max.   :7.904   Max.   :7.780  
##  Logged GDP per capita Social support   Healthy life expectancy
##  Min.   : 6.635        Min.   :0.4630   Min.   :48.48          
##  1st Qu.: 8.541        1st Qu.:0.7500   1st Qu.:59.80          
##  Median : 9.569        Median :0.8320   Median :66.60          
##  Mean   : 9.432        Mean   :0.8147   Mean   :64.99          
##  3rd Qu.:10.421        3rd Qu.:0.9050   3rd Qu.:69.60          
##  Max.   :11.647        Max.   :0.9830   Max.   :76.95          
##  Freedom to make life choices   Generosity       Perceptions of corruption
##  Min.   :0.3820               Min.   :-0.28800   Min.   :0.0820           
##  1st Qu.:0.7180               1st Qu.:-0.12600   1st Qu.:0.6670           
##  Median :0.8040               Median :-0.03600   Median :0.7810           
##  Mean   :0.7916               Mean   :-0.01513   Mean   :0.7274           
##  3rd Qu.:0.8770               3rd Qu.: 0.07900   3rd Qu.:0.8450           
##  Max.   :0.9700               Max.   : 0.54200   Max.   :0.9390           
##  Ladder score in Dystopia Explained by: Log GDP per capita
##  Min.   :2.43             Min.   :0.0000                  
##  1st Qu.:2.43             1st Qu.:0.6660                  
##  Median :2.43             Median :1.0250                  
##  Mean   :2.43             Mean   :0.9772                  
##  3rd Qu.:2.43             3rd Qu.:1.3230                  
##  Max.   :2.43             Max.   :1.7510                  
##  Explained by: Social support Explained by: Healthy life expectancy
##  Min.   :0.0000               Min.   :0.0000                       
##  1st Qu.:0.6470               1st Qu.:0.3570                       
##  Median :0.8320               Median :0.5710                       
##  Mean   :0.7933               Mean   :0.5202                       
##  3rd Qu.:0.9960               3rd Qu.:0.6650                       
##  Max.   :1.1720               Max.   :0.8970                       
##  Explained by: Freedom to make life choices Explained by: Generosity
##  Min.   :0.0000                             Min.   :0.000           
##  1st Qu.:0.4090                             1st Qu.:0.105           
##  Median :0.5140                             Median :0.164           
##  Mean   :0.4987                             Mean   :0.178           
##  3rd Qu.:0.6030                             3rd Qu.:0.239           
##  Max.   :0.7160                             Max.   :0.541           
##  Explained by: Perceptions of corruption Dystopia + residual
##  Min.   :0.0000                          Min.   :0.648      
##  1st Qu.:0.0600                          1st Qu.:2.138      
##  Median :0.1010                          Median :2.509      
##  Mean   :0.1351                          Mean   :2.430      
##  3rd Qu.:0.1740                          3rd Qu.:2.794      
##  Max.   :0.5470                          Max.   :3.482

#Question 1: What factors affect the happiness score?

#We changed Ladder score to Happiness_Score and select 7 variables for Data Analysis
data <- df %>% mutate(Happiness_Score = `Ladder score`) %>% select(Happiness_Score, `Logged GDP per capita`, `Social support`, `Healthy life expectancy`, `Freedom to make life choices`, Generosity, `Perceptions of corruption`)
corr_score <- cor(data, use = 'complete', method = 'pearson')
corrplot(corr_score)

To answer the question, we selected 7 numeric variables in the dataset to look at the correlations between them. We created a correlation matrix and plotted a heatmap for some additional insights. The size and the code of the circles indicate the level of correlation between variables. According to this heatmap, we see that there are strong relationship from ‘Logged GDP per capita’, ‘Social support’, ‘Healthy life expectancy’ with the Happiness score. ‘Generosity’ and ‘Perception of corruption’ appears to be the least correlated with the Happiness score.

library(gclus)
data.col <- dmat.color(corr_score)
order_corr <- order.single(corr_score)
cpairs(data, order_corr, panel.colors= data.col, gap=0.6, main = "Correlation of rearranged variables" )

The heatmap with big circle did not show the order of the correlation. This new scatter plot matrix rearranged the varriables so that those with higher correlation are closer to the principal diagonal. The color code of the cells reflect the level of the correlations. This graph shows that Life Expectancy and Logged GdP per capita has the highest correlation, then Happiness score. The lowest correlation are Perceptions of corruption and Generosity. So according to this dataset, Perceptions of corruption and Generosity variables are not important factors as GDP per capita and Healthy Life expectancy when it comes to Happiness score.

library(scatterplot3d)
attach(data)
scatterplot3d(`Happiness_Score`, `Logged GDP per capita`, `Healthy life expectancy`, color = 'orange', main = "3D View for GDP, Happiness, Life expectancy")

We selected the 3 highest correlation variables: Happiness_Score, Logged GDP per capita, Healthy life expectancy for further analysis. We saw them in 2 dimensions and they each linearly correlated to each other. In the 3 dimesional view, these 3 variables also show a positive linear relationship. The higher the Happiness_Score, the higher the other 2 variables are.

figure2 <- plot_ly(data, x = ~`Logged GDP per capita`, y=~`Happiness_Score`, z= ~`Healthy life expectancy`)
figure2 <- figure2 %>% add_markers()
figure2 <- figure2 %>% layout(title = "3D View for GDP, Happiness, Life expectancy")
figure2

This 3D interactive plot also help looking at the data from multiple angles in 3d. Each dot is a country being mapped into 3 dimensional space and the coordinates of the dots are the values for Happiness score, Life Expectancy and the Logged GDP per capita.

#Question 2: Are countries with high GdP per capita resulted in higher Happiness score?

#Country with highest Logged GDP per capita
maxGDP <- max(df$`Logged GDP per capita`)
df[df$`Logged GDP per capita` == maxGDP,]
## # A tibble: 1 x 20
##   `Country name` `Regional indic~ `Ladder score` `Standard error~ upperwhisker
##   <chr>          <chr>                     <dbl>            <dbl>        <dbl>
## 1 Luxembourg     Western Europe             7.32            0.037         7.40
## # ... with 15 more variables: lowerwhisker <dbl>, `Logged GDP per
## #   capita` <dbl>, `Social support` <dbl>, `Healthy life expectancy` <dbl>,
## #   `Freedom to make life choices` <dbl>, Generosity <dbl>, `Perceptions of
## #   corruption` <dbl>, `Ladder score in Dystopia` <dbl>, `Explained by: Log GDP
## #   per capita` <dbl>, `Explained by: Social support` <dbl>, `Explained by:
## #   Healthy life expectancy` <dbl>, `Explained by: Freedom to make life
## #   choices` <dbl>, `Explained by: Generosity` <dbl>, `Explained by:
## #   Perceptions of corruption` <dbl>, `Dystopia + residual` <dbl>
#Country with lowest Logged GDP per capita score
minGDP<- min(df$`Logged GDP per capita`)
df[df$`Logged GDP per capita` == minGDP,]
## # A tibble: 1 x 20
##   `Country name` `Regional indic~ `Ladder score` `Standard error~ upperwhisker
##   <chr>          <chr>                     <dbl>            <dbl>        <dbl>
## 1 Burundi        Sub-Saharan Afr~           3.78            0.107         3.98
## # ... with 15 more variables: lowerwhisker <dbl>, `Logged GDP per
## #   capita` <dbl>, `Social support` <dbl>, `Healthy life expectancy` <dbl>,
## #   `Freedom to make life choices` <dbl>, Generosity <dbl>, `Perceptions of
## #   corruption` <dbl>, `Ladder score in Dystopia` <dbl>, `Explained by: Log GDP
## #   per capita` <dbl>, `Explained by: Social support` <dbl>, `Explained by:
## #   Healthy life expectancy` <dbl>, `Explained by: Freedom to make life
## #   choices` <dbl>, `Explained by: Generosity` <dbl>, `Explained by:
## #   Perceptions of corruption` <dbl>, `Dystopia + residual` <dbl>
ggplot(df, aes(x=`Logged GDP per capita`, y=`Ladder score`)) + geom_point(aes(color = `Regional indicator`), size=2) + geom_smooth(method = 'lm') + 
  labs(x='Logged GDP per capita', y= 'Happiness score', title = 'Are high GDP countries happy countries?')
## `geom_smooth()` using formula 'y ~ x'

According to the scatter plot above, we found that countries with higher ‘Logged GDP per capita’ tends to have higher Happiness score. These 2 variables have positive linear relationship. Most of the countries with high GDP per capita are in Western Europe and North America regions. Teh countries with low Happiness score are mostly in Sub-Saharan Africa and South Asia regions.

#Question 3: Do countries with low perception of corruption have better Happiness score?

ggplot(df, aes(x=`Perceptions of corruption`, y = `Ladder score`)) + geom_point(aes(color = `Regional indicator`), size=2) + geom_smooth(method = 'lm') + 
  labs(x='Perception of corruption', y='Happiness score', title = 'Perceptions of corruption vs Happiness score?')
## `geom_smooth()` using formula 'y ~ x'

This plot shows that the linear line has a negative slope, indicate opposite correlation between Perception of corruption vs Happiness score. It tends to validate the common perception. Western Europe has low Perceptions of corruption and higher Happiness score, whereas, Countries from Sub-Saharan Africa have higher Corruption and Lower Happiness score. The Linear Relationship in there two variables are not as strongg as the slope is not steep and the scatter plot has more dots concentrated on the upper right quadrant.

#Question 4: Build a Machine Learning model to predict Life Expectancy for a country base on other variables

Data Splitting

The first step in building regression models is to split our original data into a training and test set. We then perform all feature engineering and model fitting tasks on the training set and use the test set as an independent assessment of our model’s prediction accuracy.

We will be using the initial_split() function from rsample to partition the World Happiness 2021 data into training and test sets. We use set.seed() to ensure the results are reproducible.

set.seed(580)

# Create a split object
data_split <- initial_split(data, prop = 0.75, 
                                   strata = Happiness_Score)

# Build training data set
data_training <- data_split %>% 
                        training()

# Build testing data set
data_test <- data_split %>% 
                    testing()

Model Specification

The next step in the process is to build a linear regression model object to which we fit our training data. The parsnip package from tidymodels acts like an aggregator across the various modeling engines within R. This makes it easy to implement machine learning algorithms from different R packages with one unifying syntax.

To specify a model object with parsnip, we completed these steps:

  1. Pick a model type
  2. Set the engine
  3. Set the mode (either regression or classification)

Linear regression is implemented with the linear_reg() function in parsnip. To the set the engine and mode, we use set_engine() and set_mode() respectively. Each one of these functions takes a parsnip object as an argument and updates its properties.

We create a linear regression model object with the lm engine.

lm_model <- linear_reg() %>% 
            set_engine('lm') %>% # adds lm implementation of linear regression
            set_mode('regression')

# View object properties
lm_model
## Linear Regression Model Specification (regression)
## 
## Computational engine: lm

Fitting to Training Data

The code below trains our linear regression model on the data_training data. In our formula, we have specified that Healthy life expectancy is the response variable, and the rest are our predictor variables.

We have assigned the name lm_fit to our trained linear regression model.

lm_fit <- lm_model %>% 
          fit(`Healthy life expectancy` ~ ., data = data_training)

# View lm_fit properties
lm_fit
## parsnip model object
## 
## Fit time:  0ms 
## 
## Call:
## stats::lm(formula = `Healthy life expectancy` ~ ., data = data)
## 
## Coefficients:
##                    (Intercept)                 Happiness_Score  
##                        21.7361                          0.2939  
##        `Logged GDP per capita`                `Social support`  
##                         3.6650                          9.0844  
## `Freedom to make life choices`                      Generosity  
##                         2.8762                         -1.1109  
##    `Perceptions of corruption`  
##                        -3.4546

Exploring Training Results

The lm_fit object is list that contains all of the information about how our model was trained as well as the detailed results. The names() function printed out the named objects that are stored within lm_fit. The important objects are fit and preproc. These contain the trained model and pre-processing steps (if any are used), respectively.

names(lm_fit)
## [1] "lvl"     "spec"    "fit"     "preproc" "elapsed"

To print a summary of our model, we extract fit from lm_fit and pass it to the summary() function. We explore the estimated coefficients, F-statistics, p-values, residual standard error (also known as RMSE) and R2 value. Below, we used the pluck() function from dplyr to extract the fitresults from lm_fit. This is the same as using lm_fit$fit or lm_fit[['fit']].

lm_fit %>% 
  # Extract fit element from the list
  pluck('fit') %>% 
  # Pass to summary function
  summary()
## 
## Call:
## stats::lm(formula = `Healthy life expectancy` ~ ., data = data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -10.0744  -1.9134   0.1124   2.4796   5.3576 
## 
## Coefficients:
##                                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                     21.7361     4.2728   5.087 1.58e-06 ***
## Happiness_Score                  0.2939     0.5779   0.509   0.6121    
## `Logged GDP per capita`          3.6650     0.5035   7.279 6.16e-11 ***
## `Social support`                 9.0844     5.0124   1.812   0.0728 .  
## `Freedom to make life choices`   2.8762     3.7283   0.771   0.4422    
## Generosity                      -1.1109     2.5223  -0.440   0.6605    
## `Perceptions of corruption`     -3.4546     2.0654  -1.673   0.0974 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.337 on 106 degrees of freedom
## Multiple R-squared:  0.7661, Adjusted R-squared:  0.7529 
## F-statistic: 57.87 on 6 and 106 DF,  p-value: < 2.2e-16
par(mfrow=c(2,2)) # plot all 4 plots in one

lm_fit %>% 
  pluck('fit') %>% 
  plot(pch = 16, col = '#006EA1') 

# Data frame of estimated coefficients
tidy(lm_fit)
## # A tibble: 7 x 5
##   term                           estimate std.error statistic  p.value
##   <chr>                             <dbl>     <dbl>     <dbl>    <dbl>
## 1 (Intercept)                      21.7       4.27      5.09  1.58e- 6
## 2 Happiness_Score                   0.294     0.578     0.509 6.12e- 1
## 3 `Logged GDP per capita`           3.67      0.504     7.28  6.16e-11
## 4 `Social support`                  9.08      5.01      1.81  7.28e- 2
## 5 `Freedom to make life choices`    2.88      3.73      0.771 4.42e- 1
## 6 Generosity                       -1.11      2.52     -0.440 6.61e- 1
## 7 `Perceptions of corruption`      -3.45      2.07     -1.67  9.74e- 2
# Performance metrics on training data
glance(lm_fit)
## # A tibble: 1 x 12
##   r.squared adj.r.squared sigma statistic  p.value    df logLik   AIC   BIC
##       <dbl>         <dbl> <dbl>     <dbl>    <dbl> <dbl>  <dbl> <dbl> <dbl>
## 1     0.766         0.753  3.34      57.9 3.18e-31     6  -293.  602.  624.
## # ... with 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>
#vip(lm_fit)

According to the Summary report and the Bar graph, Logged GDP per capita is the most important to the Linear Model to predict the Healthy Life Expectancy. “Generosity” and “Happiness_Score” are not a strong indicator for healthy life expectancy.

Evaluating Test Set Accuracy

To assess the accuracy of our trained linear regression model, lm_fit, we must use it to make predictions on our test data, data_test.

This is done with the predict() function from parnsip. This function takes two important arguments:

The code below uses the predict function to generate a data frame with a single column, .pred, which contains the predicted Healthy life expectancy values on the data_test data.

predict(lm_fit, new_data = data_test)
## # A tibble: 36 x 1
##    .pred
##    <dbl>
##  1  70.8
##  2  72.4
##  3  71.8
##  4  71.5
##  5  72.5
##  6  70.6
##  7  69.7
##  8  64.3
##  9  67.2
## 10  71.4
## # ... with 26 more rows

Generally it’s best to combine the test data set and the predictions into a single data frame. We create a data frame with the predictions on the data_test data and then use bind_cols to add the data_test data to the results.

Now we have the model results and the test data in a single data frame.

data_test_results <- predict(lm_fit, new_data = data_test) %>% 
                            bind_cols(data_test)

# View results
data_test_results
## # A tibble: 36 x 8
##    .pred Happiness_Score `Logged GDP per~ `Social support` `Healthy life e~
##    <dbl>           <dbl>            <dbl>            <dbl>            <dbl>
##  1  70.8            7.16            10.6             0.939             73.5
##  2  72.4            6.95            11.0             0.92              68.2
##  3  71.8            6.83            10.8             0.906             72.2
##  4  71.5            6.60            10.7             0.931             72.2
##  5  72.5            6.56            11.1             0.844             67.3
##  6  70.6            6.49            10.6             0.932             74.7
##  7  69.7            6.48            10.6             0.88              73.8
##  8  64.3            6.37             9.32            0.821             63.8
##  9  67.2            6.32             9.86            0.831             68.6
## 10  71.4            6.19            10.5             0.941             68.8
## # ... with 26 more rows, and 3 more variables: `Freedom to make life
## #   choices` <dbl>, Generosity <dbl>, `Perceptions of corruption` <dbl>

Calculating RMSE and R2 on the Test Data

To obtain the RMSE and R2 values on our test set results, we use the rmse() and rsq() functions.

Both functions take the following arguments:

  • data - a data frame with columns that have the true values and predictions
  • truth - the column with the true response values
  • estimate - the column with predicted values

In the examples below we pass our data_test_results to these functions to obtain these values for our test set. results are always returned as a data frame with the following columns: .metric, .estimator, and .estimate.

# RMSE on test set
rmse(data_test_results, 
     truth = `Healthy life expectancy`,
     estimate = .pred)
## # A tibble: 1 x 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 rmse    standard        3.57
# R2 on test set
rsq(data_test_results,
    truth = `Healthy life expectancy`,
    estimate = .pred)
## # A tibble: 1 x 3
##   .metric .estimator .estimate
##   <chr>   <chr>          <dbl>
## 1 rsq     standard       0.738

R2 Plot

The best way to assess the test set accuracy is by making an R2 plot. This is a plot that can be used for any regression model.

It plots the actual values (Healthy life expectancy) versus the model predictions (.pred) as a scatter plot. It also plot the line y = x through the origin. This line is a visually representation of the perfect model where all predicted values are equal to the true values in the test set. The farther the points are from this line, the worse the model fit.

The reason this plot is called an R2 plot, is because the R2 is simply the squared correlation between the true and predicted values, which are plotted as paired in the plot.

In the code below, we use geom_point() and geom_abline() to make this plot using out data_test_results data. The geom_abline() function will plot a line with the provided slope and intercept arguments. The coord_obs_pred() function scales the x and y axis to have the same range for accurate comparisons.

ggplot(data = data_test_results,
       mapping = aes(x = .pred, y = `Healthy life expectancy`)) +
  geom_point(alpha = 0.4) +
  geom_abline(intercept = 0, slope = 1, linetype = 2, color = 'red') +
  coord_obs_pred() +
  labs(title = 'Linear Regression Results - data Test Set',
       x = 'Predicted Healthy life expectancy',
       y = 'Actual Healthy life expectancy') +
  theme_light()

#Extra: Do countries with higher Logged GDP per capita also have higher Healthy life expectancy? Build a Machine Learning model to predict Life Expectancy base on Happiness score.

lm_model = lm(`Healthy life expectancy`~ `Logged GDP per capita`,data=data)
coef(lm_model)
##             (Intercept) `Logged GDP per capita` 
##               17.679500                5.016142
summary(lm_model)
## 
## Call:
## lm(formula = `Healthy life expectancy` ~ `Logged GDP per capita`, 
##     data = data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -12.3178  -1.9328   0.5148   2.3822   6.7384 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              17.6795     2.3384    7.56    4e-12 ***
## `Logged GDP per capita`   5.0161     0.2461   20.38   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.469 on 147 degrees of freedom
## Multiple R-squared:  0.7387, Adjusted R-squared:  0.7369 
## F-statistic: 415.5 on 1 and 147 DF,  p-value: < 2.2e-16