Skip to main content

Section 5.1 One numerical explanatory variable

Before we introduce the model needed for simple linear regression, we present an example. Why do some countries exhibit high fertility rates while others have significantly lower ones? Are there correlations between fertility rates and life expectancy across different continents and nations? Could underlying socioeconomic factors be influencing these trends?
These are all questions that are of interest to demographers and policy makers, as understanding fertility rates is important for planning and development. By analyzing the dataset of UN member states, which includes variables such as country codes (ISO), fertility rates, and life expectancy for 2022, researchers can uncover patterns and make predictions about fertility rates based on life expectancy.
In this section, we aim to explain differences in fertility rates as a function of one numerical variable: life expectancy. Could it be that countries with higher life expectancy also have lower fertility rates? Could it be instead that countries with higher life expectancy tend to have higher fertility rates? Or could it be that there is no relationship between life expectancy and fertility rates? We answer these questions by modeling the relationship between fertility rates and life expectancy using simple linear regression where we have:
  1. A numerical outcome variable \(y\) (the countryโ€™s fertility rate) and
  2. A single numerical explanatory variable \(x\) (the countryโ€™s life expectancy).

Subsection 5.1.1 Exploratory data analysis

The data on the current UN member states (as of 2024) can be found in the un_member_states_2024 data frame included in the moderndive package. However, to keep things simple we include only those rows that donโ€™t have missing data with na.omit() and select() only the subset of the variables weโ€™ll consider in this chapter, and save this data in a new data frame called UN_data_ch5:
UN_data_ch5 <- un_member_states_2024 |>
  select(iso, 
         life_exp = life_expectancy_2022, 
         fert_rate = fertility_rate_2022, 
         obes_rate = obesity_rate_2016)|>
  na.omit()
A crucial step before doing any kind of analysis or modeling is performing an exploratory data analysis, or EDA for short. EDA gives you a sense of the distributions of the individual variables in your data, whether any potential relationships exist between variables, whether there are outliers and/or missing values, and (most importantly) how to build your model. Here are three common steps in an EDA:
  1. Most crucially, looking at the raw data values.
  2. Computing summary statistics, such as means, medians, and maximums.
  3. Creating data visualizations.
We perform the first common step in an exploratory data analysis: looking at the raw data values. Because this step seems so trivial, unfortunately many data analysts ignore it. However, getting an early sense of what your raw data looks like can often prevent many larger issues down the road.
You can do this by using RStudioโ€™s spreadsheet viewer or by using the glimpse() function:
glimpse(UN_data_ch5)
Rows: 181
Columns: 4
$ iso       <chr> "AFG", "ALB", "DZA", "AGO", "ATG", "ARG", "ARM", "AUS", "AUT", "AZE", "BHS", "BHR", "BGD", "BRB", "Bโ€ฆ
$ life_exp  <dbl> 53.6, 79.5, 78.0, 62.1, 77.8, 78.3, 76.1, 83.1, 82.3, 74.2, 76.1, 79.9, 74.7, 78.5, 74.3, 81.9, 75.8โ€ฆ
$ fert_rate <dbl> 4.3, 1.4, 2.7, 5.0, 1.6, 1.9, 1.6, 1.6, 1.5, 1.6, 1.4, 1.8, 1.9, 1.6, 1.5, 1.6, 2.0, 4.7, 1.4, 2.5, โ€ฆ
$ obes_rate <dbl> 5.5, 21.7, 27.4, 8.2, 18.9, 28.3, 20.2, 29.0, 20.1, 19.9, 31.6, 29.8, 3.6, 23.1, 24.5, 22.1, 24.1, 9โ€ฆ
Observe that Rows:181 indicates that there are 181 rows/observations in UN_data_ch5 after filtering out the missing values, where each row corresponds to one observed country/member state. It is important to note that the observational unit is an individual country. Recall that the observational unit is the โ€œtype of thingโ€ that is being measured by our variables.
A full description of all the variables included in un_member_states_2024 can be found by reading the associated help file (run ?un_member_states_2024 in the console). Letโ€™s describe only the variables we selected in UN_data_ch5:
  1. iso: An identification variable used to distinguish between the countries in the filtered dataset.
  2. fert_rate: A numerical variable representing the countryโ€™s fertility rate in 2022 corresponding to the expected number of children born per woman in child-bearing years. This is the outcome variable \(y\) of interest.
  3. life_exp: A numerical variable representing the countryโ€™s average life expectancy in 2022 in years. This is the primary explanatory variable \(x\) of interest.
  4. obes_rate: A numerical variable representing the countryโ€™s obesity rate in 2016. This will be another explanatory variable \(x\) that we use in the Learning check at the end of this subsection.
An alternative way to look at the raw data values is by choosing a random sample of the rows in UN_data_ch5 by piping it into the slice_sample() function from the dplyr package. Here we set the n argument to be 5, indicating that we want a random sample of 5 rows. Note that due to the random nature of the sampling, you will likely end up with a different subset of 5 rows.
UN_data_ch5 |>

  slice_sample(n = 5)
# A tibble: 5 ร— 4
  iso   life_exp fert_rate obes_rate
  <chr>    <dbl>     <dbl>     <dbl>
1 PRT	      81.5	     1.4	    20.8
2 MNE		    77.8		   1.7	    23.3
3 CPV	    	73.8		   1.9	    11.8
4 VNM	    	75.5		   1.9	     2.1
5 IDN		    73.1	   	 2.1	     6.9
We have looked at the raw values in our UN_data_ch5 data frame and got a preliminary sense of the data. We can now compute summary statistics. We start by computing the mean and median of our numerical outcome variable fert_rate and our numerical explanatory variable life_exp. We do this by using the summarize() function from dplyr along with the mean() and median() summary functions.
UN_data_ch5 |>
  summarize(mean_life_exp = mean(life_exp), 
            mean_fert_rate = mean(fert_rate),
            median_life_exp = median(life_exp), 
            median_fert_rate = median(fert_rate))
# A tibble: 1 ร— 2
  mean_life_exp	mean_fert_rate	median_life_exp	median_fert_rate
1          73.6          	 2.5	           75.1	               2
However, what if we want other summary statistics as well, such as the standard deviation (a measure of spread), the minimum and maximum values, and various percentiles?
Typing all these summary statistic functions in summarize() would be long and tedious. Instead, we use the convenient tidy_summary() function in the moderndive package. This function takes in a data frame, summarizes it, and returns commonly used summary statistics in tidy format. We take our UN_data_ch5 data frame, select() only the outcome and explanatory variables fert_rate and life_exp, and pipe them into the tidy_summary function:
UN_data_ch5 |> 

  select(fert_rate, life_exp) |> 

  tidy_summary()
# A tibble: 2 ร— 11
  column        n group type      min    Q1  mean median    Q3   max    sd
  <chr>     <int> <chr> <chr>   <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl>
1 fert_rate   181 <NA>  numeric   1.1	  1.6	 2.5	   2.0	3.2	   6.6 1.15
2 life_exp    181 <NA>  numeric  53.6	 69.4	73.6	  75.1 78.3 	86.4 6.80
We can also do this more directly by providing which columns weโ€™d like a summary of inside the tidy_summary() function:
UN_data_ch5 |> 

  tidy_summary(columns = c(fert_rate, life_exp))
# A tibble: 2 ร— 11
  column        n group type      min    Q1  mean median    Q3   max    sd
  <chr>     <int> <chr> <chr>   <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl>
1 fert_rate   181 <NA>  numeric   1.1   1.6  2.5     2.0  3.2    6.6 1.15
2 life_exp    181 <NA>  numeric  53.6  69.4 73.6    75.1 78.3   86.4 6.80
Both return the same results for the numerical variables fert_rate and life_exp:
Looking at this output, we can see how the values of both variables distribute. For example, the median fertility rate was 2, whereas the median life expectancy was 75.14 years. The middle 50% of fertility rates was between 1.6 and 3.2 (the first and third quartiles), and the middle 50% of life expectancies was from 69.36 to 78.31.
The tidy_summary() function only returns what are known as univariate summary statistics: functions that take a single variable and return some numerical summary of that variable. However, there also exist bivariate summary statistics: functions that take in two variables and return some summary of those two variables.
In particular, when the two variables are numerical, we can compute the correlation coefficient. Generally speaking, coefficients are quantitative expressions of a specific phenomenon. A correlation coefficient measures the strength of the linear relationship between two numerical variables. Its value goes from -1 and 1 where:
  • -1 indicates a perfect negative relationship: As one variable increases, the value of the other variable tends to go down, following a straight line.
  • 0 indicates no relationship: The values of both variables go up/down independently of each other.
  • +1 indicates a perfect positive relationship: As the value of one variable goes up, the value of the other variable tends to go up as well in a linear fashion.
Figureย 5.1.1 gives examples of nine different correlation coefficient values for hypothetical numerical variables \(x\) and \(y\text{.}\)
Nine scatterplots arranged in a 3-by-3 grid showing hypothetical x and y variables with correlation coefficients ranging from -0.9999 to 0.9999.
Figure 5.1.1. Nine different correlation coefficients.
For example, observe in the top right plot that for a correlation coefficient of -0.75 there is a negative linear relationship between \(x\) and \(y\text{,}\) but it is not as strong as the negative linear relationship between \(x\) and \(y\) when the correlation coefficient is -0.9 or -1.
The correlation coefficient can be computed using the get_correlation() function in the moderndive package. In this case, the inputs to the function are the two numerical variables for which we want to calculate the correlation coefficient.
We put the name of the outcome variable on the left-hand side of the ~ โ€œtildeโ€ sign, while putting the name of the explanatory variable on the right-hand side. This is known as Rโ€™s formula notation. We will use this same โ€œformulaโ€ syntax with regression later in this chapter.
UN_data_ch5 |> 

  get_correlation(formula = fert_rate ~ life_exp)
# A tibble: 1 ร— 1
     cor
   <dbl>
1 -0.812
An alternative way to compute correlation is to use the cor() summary function within a summarize():
UN_data_ch5 |> 
  summarize(correlation = cor(fert_rate, life_exp))
In our case, the correlation coefficient of -0.812 indicates that the relationship between fertility rate and life expectancy is โ€œmoderately negative.โ€ There is a certain amount of subjectivity in interpreting correlation coefficients, especially those that are not close to the extreme values of -1, 0, and 1. To develop your intuition about correlation coefficients, play the โ€œGuess the Correlationโ€ 1980โ€™s style video game mentioned in Subsectionย 5.4.1.
We now perform the last step in EDA: creating data visualizations. Since both the fert_rate and life_exp variables are numerical, a scatterplot is an appropriate graph to visualize this data. We do this using geom_point() and display the result in Figureย 5.1.2. Furthermore, we set the alpha value to 0.1 to check for any overplotting.
ggplot(UN_data_ch5, 
       aes(x = life_exp, y = fert_rate)) +
  geom_point(alpha = 0.1) +
  labs(x = "Life Expectancy", y = "Fertility Rate")
Scatterplot showing fertility rate on the y-axis and life expectancy on the x-axis for UN member states.
Figure 5.1.2. Scatterplot of relationship of life expectancy and fertility rate.
We do not see much for overplotting due to little to no overlap in the points. Most life expectancy entries appear to fall between 70 and 80 years, while most fertility rate entries fall between 1.5 and 3.5 births. Furthermore, while opinions may vary, it is our opinion that the relationship between fertility rate and life expectancy is โ€œmoderately negative.โ€ This is consistent with our earlier computed correlation coefficient of -0.812.
We build on the scatterplot in Figureย 5.1.2 by adding a โ€œbest-fittingโ€ line: of all possible lines we can draw on this scatterplot, it is the line that โ€œbestโ€ fits through the cloud of points. We do this by adding a new geom_smooth(method = "lm", se = FALSE) layer to the ggplot() code that created the scatterplot in Figureย 5.1.2. The method = "lm" argument sets the line to be a โ€œlinear model.โ€ The se = FALSE argument suppresses standard error uncertainty bars. (Weโ€™ll define the concept of standard error later in Subsectionย 7.3.4.)
ggplot(UN_data_ch5, aes(x = life_exp, y = fert_rate)) +
  geom_point(alpha = 0.1) +
  labs(x = "Life Expectancy", 
    y = "Fertility Rate",
    title = "Relationship of life expectancy and fertility rate") +
  geom_smooth(method = "lm", se = FALSE)
Scatterplot showing fertility rate on the y-axis and life expectancy on the x-axis with a best-fit regression line.
Figure 5.1.3. Scatterplot of life expectancy and fertility rate with regression line.
The line in the resulting Figureย 5.1.3 is called a โ€œregression line.โ€ The regression line is a visual summary of the relationship between two numerical variables, in our case the outcome variable fert_rate and the explanatory variable life_exp. The negative slope of the blue line is consistent with our earlier observed correlation coefficient suggesting that there is a negative relationship between these two variables: as a countryโ€™s population has higher life expectancy it tends to have a lower fertility rate. Weโ€™ll see later, however, that while the correlation coefficient and the slope of a regression line always have the same sign (positive or negative), they typically do not have the same value.
Furthermore, a regression line is โ€œbest-fittingโ€ in that it minimizes some mathematical criteria. We present these mathematical criteria in Subsectionย 5.3.2, but we suggest you read this subsection only after first reading the rest of this section on regression with one numerical explanatory variable.

Exercises Exercises

1.
Conduct a new exploratory data analysis with the same outcome variable \(y\) being fert_rate but with obes_rate as the new explanatory variable \(x\text{.}\) Remember, this involves three things:
  1. Looking at the raw data values.
  2. Computing summary statistics.
  3. Creating data visualizations.
What can you say about the relationship between obesity rate and fertility rate based on this exploration?
Answer.
# 1) Look at raw values
glimpse(UN_data_ch5)

# 2) Summary statistics
UN_data_ch5 |>
  select(fert_rate, obes_rate) |>
  tidy_summary()

# 3) Visualizations
ggplot(UN_data_ch5, aes(x = obes_rate, y = fert_rate)) +
  geom_point(alpha = 0.2) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(x = "Obesity rate (2016)", y = "Fertility rate (2022)")

# Optional: correlation
UN_data_ch5 |>
  get_correlation(fert_rate ~ obes_rate)
EDA = raw data + summaries + plot. The scatterplot with the regression line and the correlation quantify direction/strength. This data shows a negative association between obesity rate and fertility rate (points slope down; negative correlation): as obesity rate increases, fertility rate tends to decrease.
2.
What is the main purpose of performing an exploratory data analysis (EDA) before fitting a regression model?
  1. To predict future values.
  2. To understand the relationship between variables and detect potential issues.
  3. To create more variables.
  4. To generate random samples.
Answer.
B. EDA helps you understand relationships, spot outliers/missingness, and check assumptions before modeling, not to predict or fabricate variables.

Subsection 5.1.2 Simple linear regression

You may recall from secondary/high school algebra that the equation of a line is \(y = a + b\cdot x\text{.}\) (Note that the \(\cdot\) symbol is equivalent to the \(\times\) โ€œmultiply byโ€ mathematical symbol. Weโ€™ll use the \(\cdot\) symbol in the rest of this book as it is more succinct.) It is defined by two coefficients \(a\) and \(b\text{.}\) The intercept coefficient \(a\) is the value of \(y\) when \(x = 0\text{.}\) The slope coefficient \(b\) for \(x\) is the increase in \(y\) for every increase of one in \(x\text{.}\) This is also called the โ€œrise over run.โ€
However, when defining a regression line like the one in Figureย 5.1.3, we use slightly different notation: the equation of the regression line is \(\widehat{y} = b_0 + b_1 \cdot x\). The intercept coefficient is \(b_0\text{,}\) so \(b_0\) is the value of \(\widehat{y}\) when \(x = 0\text{.}\) The slope coefficient for \(x\) is \(b_1\text{,}\) i.e., the increase in \(\widehat{y}\) for every increase of one in \(x\text{.}\) Why do we put a โ€œhatโ€ on top of the \(y\text{?}\) Itโ€™s a form of notation commonly used in regression to indicate that we have a fitted value, or the value of \(y\) on the regression line for a given \(x\) value as discussed further in Subsectionย 5.1.3.
We know that the regression line in Figureย 5.1.3 has a negative slope \(b_1\) corresponding to our explanatory \(x\) variable life_exp. Why? Because as countries tend to have higher life_exp values, they tend to have lower fert_rate values. However, what is the numerical value of the slope \(b_1\text{?}\) What about the intercept \(b_0\text{?}\) We do not compute these two values by hand, but rather we use a computer!
We can obtain the values of the intercept \(b_0\) and the slope for life_exp \(b_1\) by outputting the linear regression coefficients. This is done in two steps:
  1. We first โ€œfitโ€ the linear regression model using the lm() function and save it in demographics_model.
  2. We get the regression coefficients by applying coef() to demographics_model.
# Fit regression model:
demographics_model <- lm(fert_rate ~ life_exp, data = UN_data_ch5)
# Get regression coefficients
coef(demographics_model)
We first focus on interpreting the regression coefficients, and later revisit the code that produced it. The coefficients are the intercept \(b_0\) and the slope \(b_1\) for life_exp. Thus the equation of the regression line in Figureย 5.1.3 follows:
\begin{align*} \widehat{y} \amp= b_0 + b_1 \cdot x\\ \widehat{\text{fertility\_rate}} \amp= b_0 + b_{\text{life\_expectancy}} \cdot \text{life\_expectancy}\\ \widehat{\text{fertility\_rate}} \amp= 12.599 + (-0.137) \cdot \text{life\_expectancy} \end{align*}
The intercept \(b_0 = 12.599\) is the average fertility rate \(\widehat{y} = \widehat{\text{fertility\_rate}}\) for those countries that had a life_exp of 0. Or in graphical terms, where the line intersects the \(y\) axis for \(x = 0\text{.}\) Note, however, that while the intercept of the regression line has a mathematical interpretation, it has no practical interpretation here, since observing a life_exp of 0 is impossible. Furthermore, looking at the scatterplot with the regression line in Figureย 5.1.3, no countries had a life expectancy anywhere near 0.
Of greater interest is the slope \(b_{\text{life\_expectancy}}\) for life_exp of \(-0.137\text{.}\) This summarizes the relationship between the fertility rate and life expectancy variables. Note that the sign is negative, suggesting a negative relationship between these two variables. This means countries with higher life expectancies tend to have lower fertility rates. Recall that the correlation coefficient is -0.812. They both have the same negative sign, but have a different value. Recall also that the correlationโ€™s interpretation is the โ€œstrength of linear association.โ€ The slopeโ€™s interpretation is a little different:
For every increase of 1 unit in life_exp, there is an associated decrease of, on average, 0.137 units of fert_rate.
We only state that there is an associated increase and not necessarily a causal increase. Perhaps it may not be that higher life expectancies directly cause lower fertility rates. Instead, wealthier countries could tend to have stronger educational backgrounds, improved health, a higher standard of living, and have lower fertility rates, while at the same time these wealthy countries also tend to have higher life expectancies. Just because two variables are strongly associated, it does not necessarily mean that one causes the other. This is summed up in the often-quoted phrase, โ€œcorrelation is not necessarily causation.โ€ We discuss this idea further in Subsectionย 5.3.1.
Furthermore, we say that this associated decrease is on average 0.137 units because you might have two countries whose life_exp values differ by 1 unit, but their difference in fertility rates may not be exactly \(-0.137\text{.}\) What the slope of \(-0.137\) is saying is that across all possible countries, the average difference in fertility rate between two countries whose life expectancies differ by one is \(-0.137\text{.}\)
Now that we have learned how to compute the equation for the regression line in Figureย 5.1.3 using the model coefficient values and how to interpret the resulting intercept and slope, we revisit the code that generated these coefficients:
# Fit regression model:
demographics_model <- lm(fert_rate ~ life_exp, data = UN_data_ch5)
# Get regression coefficients:
coef(demographics_model)
First, we โ€œfitโ€ the linear regression model to the data using the lm() function and save this as demographics_model. When we say โ€œfit,โ€ we mean โ€œfind the best fitting line to this data.โ€ lm() stands for โ€œlinear modelโ€ and is used as lm(y ~ x, data = df_name) where:
  • y is the outcome variable, followed by a tilde ~. In our case, y is set to fert_rate.
  • x is the explanatory variable. In our case, x is set to life_exp.
  • The combination of y ~ x is called a model formula. (Note the order of y and x.) In our case, the model formula is fert_rate ~ life_exp. We saw such model formulas earlier with the get_correlation() function in Subsectionย 5.1.1.
  • df_name is the name of the data frame that contains the variables y and x. In our case, data is the UN_data_ch5 data frame.
Second, we take the saved model in demographics_model and apply the coef() function to it to obtain the regression coefficients. This gives us the components of the regression equation line: the intercept \(b_0\) and the slope \(b_1\text{.}\)

Exercises Exercises

1.
Fit a simple linear regression using lm(fert_rate ~ obes_rate, data = UN_data_ch5) where obes_rate is the new explanatory variable \(x\text{.}\) Learn about the โ€œbest-fittingโ€ line from the regression coefficients by applying the coef() function. How do the regression results match up with your earlier exploratory data analysis?
Answer.
m_obesity <- lm(fert_rate ~ obes_rate, data = UN_data_ch5)

coef(m_obesity)

# or a tidy table:

get_regression_table(m_obesity)
(Intercept)   obes_rate 
 2.69794151 -0.02037804 
# A tibble: 2 ร— 7
  term      estimate std_error statistic p_value lower_ci upper_ci
  <chr>        <dbl>     <dbl>     <dbl>   <dbl>    <dbl>    <dbl>
1 intercept     2.70     0.157     17.2    0        2.39     3.01 
2 obes_rate    -0.02     0.006     -3.15   0.002   -0.033   -0.008
The slope sign should match your EDA: typically negative, meaning higher obesity rate is associated with lower fertility. The magnitude tells how much fertility changes per 1-point increase in obesity (on average). If your plot/correlation looked negative, a negative fitted slope confirms that.
2.
What does the intercept term \(b_0\) represent in simple linear regression?
  1. The change in the outcome for a one-unit change in the explanatory variable.
  2. The predicted value of the outcome when the explanatory variable is zero.
  3. The standard error of the regression.
  4. The correlation between the outcome and explanatory variables.
Answer.
B. \(b_0\) is the predicted response when \(x = 0\). It may be outside the dataโ€™s range (so often not substantively meaningful), but thatโ€™s the definition.
3.
What best describes the โ€œslopeโ€ of a simple linear regression line?
  1. The increase in the explanatory variable for a one-unit increase in the outcome.
  2. The average of the explanatory variable.
  3. The change in the outcome for a one-unit increase in the explanatory variable.
  4. The minimum value of the outcome variable.
Answer.
C. The slope is the change in the outcome for a one-unit increase in the explanatory variable, on average.
4.
What does a negative slope in a simple linear regression indicate?
  1. The outcome variable decreases as the explanatory variable increases.
  2. The explanatory variable remains constant as the outcome variable increases.
  3. The correlation coefficient is zero.
  4. The outcome variable increases as the explanatory variable increases.
Answer.
A. As \(x\) increases, the predicted \(y\) decreases (downward trend).

Subsection 5.1.3 Observed/fitted values and residuals

We just saw how to get the value of the intercept and the slope of a regression line from the output of the coef() function. Now instead say we want information on individual observations. For example, we focus on the 21st of the countries in the UN_data_ch5 data frame in Table Tableย 5.1.4. This corresponds to the UN member state of Bosnia and Herzegovina (BIH).
Table 5.1.4. Data for the 21st country out of 193.
iso life_exp fert_rate obes_rate
BIH 78 1.3 17.9
What is the value \(\widehat{y}\) on the regression line corresponding to this countryโ€™s life_exp value? In Figureย 5.1.5 we mark three values corresponding to these results for Bosnia and Herzegovina and give their statistical names:
  • Circle: The observed value \(y = 1.3\) is this countryโ€™s actual fertility rate.
  • Square: The fitted value \(\widehat{y}\) is the value on the regression line for that \(x = \texttt{life\_exp} = 77.98\) value, computed with the intercept and slope in the regression table:
    \begin{equation*} \widehat{y} = b_0 + b_1 \dot x = 12.599 + (-0.137) \dot 77.98 = 1.894 \end{equation*}
  • Arrow: The length of this arrow is the residual and is computed by subtracting the fitted value \(\widehat{y}\) from the observed value \(y\text{.}\) The residual can be thought of as a modelโ€™s error or โ€œlack of fitโ€ for a particular observation. In the case of this country \(y-\widehat{y} = 1.3 - 1.894 = -0.594\)
Scatterplot with a highlighted point for Bosnia and Herzegovina showing the observed value (circle), fitted value (square), and residual (arrow).
Figure 5.1.5. Example of observed value, fitted value, and residual.
Now say we want to compute both the fitted value \(\widehat{y} = b_0 + b_1 \cdot x\) and the residual \(y - \widehat{y}\) for all UN member states with complete data as of 2024. Recall that each country corresponds to one of the rows in the UN_data_ch5 data frame and also one of the points in the regression plot in Figureย 5.1.5.
We could repeat the previous calculations we performed by hand for all countries, but that would be tedious and time consuming. Instead, we use a computer with the get_regression_points() function. We apply the get_regression_points() function to demographics_model, which is where we saved our lm() model in the previous section. In Tableย 5.1.6 we present the results of only the 21st through 24th courses for brevity.
regression_points <- get_regression_points(demographics_model)

regression_points
Table 5.1.6. Regression points (for only the 21st through 24th countries)
ID fert_rate life_exp fert_rate_hat residual
21 1.3 78.0 1.89 -0.594
22 2.7 65.6 3.59 -0.888
23 1.6 75.9 2.18 -0.576
24 1.7 80.6 1.53 0.165
This function is an example of what is known in computer programming as a wrapper function. It takes other pre-existing functions and โ€œwrapsโ€ them into a single function that hides its inner workings. This concept is illustrated in Figureย 5.1.7.
Diagram illustrating the concept of a wrapper function with inputs and outputs visible but internals hidden.
Figure 5.1.7. The concept of a wrapper function.
So all you need to worry about is what the inputs look like and what the outputs look like; you leave all the other details โ€œunder the hood of the car.โ€ In our regression modeling example, the get_regression_points() function takes a saved lm() linear regression model as input and returns a data frame of the regression predictions as output. If you are interested in learning more about the get_regression_points() functionโ€™s inner workings, check out Subsectionย 5.3.3.
We inspect the individual columns and match them with the elements of Figureย 5.1.5:
  • The fert_rate column represents the observed outcome variable \(y\text{.}\) This is the y-position of the 181 black points.
  • The life_exp column represents the values of the explanatory variable \(x\text{.}\) This is the x-position of the 181 black points.
  • The fert_rate_hat column represents the fitted values \(\widehat{y}\text{.}\) This is the corresponding value on the regression line for the 181 \(x\) values.
  • The residual column represents the residuals \(y - \widehat{y}\text{.}\) This is the 181 vertical distances between the 181 black points and the regression line.
Just as we did for the 21st country in the UN_data_ch5 dataset, we repeat the calculations for the 24th country. This corresponds to the country of Brunei (BRN):
  • fert_rate \(= 1.7\) is the observed fert_rate \(y\) for this country.
  • life_exp \(= 80.590\) is the value of the explanatory variable life_exp \(x\) for Brunei.
  • fert_rate_hat \(= 1.535 = 12.599 + (-0.137) \dot 80.590\) is the fitted value \(\widehat{y}\) on the regression line for this country.
  • residual \(= 0.165 = 1.7 - 1.535\) is the value of the residual for this country. In other words, the modelโ€™s fitted value was off by the residual value in fertility rate units for Brunei.
If you like, you can skip ahead to Subsectionย 5.3.2 to learn about the processes behind what makes โ€œbest-fittingโ€ regression lines. As a primer, a โ€œbest-fittingโ€ line refers to the line that minimizes the sum of squared residuals out of all possible lines we can draw through the points. In Sectionย 5.2, weโ€™ll discuss another common scenario of having a categorical explanatory variable and a numerical outcome variable.

Exercises Exercises

1.
What is a โ€œwrapper functionโ€ in the context of statistical modeling in R?
  1. A function that directly fits a regression model without using any other functions.
  2. A function that combines other functions to simplify complex operations and provide a user-friendly interface.
  3. A function that removes missing values from a dataset before analysis.
  4. A function that only handles categorical data in regression models.
Answer.
B. Wrapper functions combine other functions into a simpler interface (e.g., get_regression_points() wraps broom::augment() and some cleaning).
2.
Generate a data frame of the residuals of the Learning check model where you used obes_rate as the explanatory \(x\) variable.
Answer.
m_obesity <- lm(fert_rate ~ obes_rate, data = UN_data_ch5)
resids_df <- get_regression_points(m_obesity)
resids_df |> select(obes_rate, fert_rate, fert_rate_hat, residual) |> head()
get_regression_points() returns observed \(y\text{,}\) fitted \(\hat{y}\text{,}\) and residuals \(y - \hat{y}\) in a tidy frame, perfect for diagnostics and sorting.
3.
Which of the following statements is true about the regression line in a simple linear regression model?
  1. The regression line represents the average of the outcome variable.
  2. The regression line minimizes the sum of squared differences between the observed and predicted values.
  3. The regression line always has a slope of zero.
  4. The regression line is only useful when there is no correlation between variables.
Answer.
B. OLS chooses the line that minimizes the sum of squared residuals (squared differences between observed and fitted).