Introduction to macroeconomics

NOTE: The present notebook is coded with quarto, in the R programming language. The white margin to the right will be used to display code output. To access World Bank data using python, we recommend this short colab notebook.

This document relies heavily on the {tidyverse} ecosystem of packages. We load the tidyverse below as a prerequisite for the rest of the notebook - along with a few other important libraries.

To install packages, use the install.packages() function as below (commented on purpose).

# install.packages("tidyverse")

Once they are installed, we can call/load/activate them in the current session.

library(tidyverse)  # Package for data wrangling
library(readxl)     # Package to import MS Excel files
library(latex2exp)  # Package for LaTeX expressions
library(quantmod)   # Package for stock data extraction
library(plotly)     # For interactive plots
library(ggsci)      # For addition color palettes

\(\rightarrow\) Don’t forget that code flows sequentially. A random chunk may not work if the previous ones have have not been executed.

1 Topics in macroeconomics

Macroeconomics is a vast discipline. There are many valuable textbooks on the matter, but we take for instance the recent and excellent Advanced Macroeconomics - An Easy Guide - CSV2021 henceforth (initials of authors). It will guide us all along the way. Its content is divided into the following sections:

  • Growth Theory
  • Growth theory preliminaries
  • The neoclassical growth model
  • An application: The small open economy
  • Endogenous growth models I: Escaping diminishing returns (with human capital)
  • Endogenous growth models II: Technological change
  • Proximate and fundamental causes of growth
  • Overlapping Generations Models
  • Overlapping generations models
  • An application: Pension systems and transitions
  • Unified growth theory
  • Consumption and Investment
  • Consumption
  • Consumption under uncertainty and macro finance
  • Investment
  • Short Term Fluctuations
  • Real business cycles
  • (New) Keynesian theories of fluctuations: A primer
  • Unemployment
  • Monetary and Fiscal Policy
  • Fiscal policy I: Public debt and the effectiveness of fiscal policy
  • Fiscal policy II: The long-run determinants of fiscal policy
  • Monetary policy: An introduction
  • Rules vs Discretion
  • Recent debates in monetary policy
  • New developments in monetary and fiscal policy

In the present course, we will cover those in green. For the sake of consistency, we will often keep the same notations as CSV2021.

We also recommend the older monographs Economic Growth by Barro and Sala-ì-Martin and Advanced Macroeconomics by Romer.

2 Empirical overview

The aim of any model is to depict or predict salient empirical facts. In order to test the validity of models, we need data.

There are many sources from which we can obtain macroeconomic data and many are national or international institutions. Some are more practical and user-friendly than others, especially via their API services.
We mention for instance:

Below, we will use the first one because we feel it is the most user-friendly and does not require any authentication.

We list the indicators (from the World Bank) we’ll study below:

The data starts in 1960 and for simplicity, we focus on two countries, France and the United States. To add other countries, you need to specify their ISO alpha-2 codes.
The chunk below fetches the data. It can take up to 30 seconds to run.

library(WDI)
wb_raw = WDI(indicator = c("gdp_per_capita" = "NY.GDP.PCAP.KD",
                            "population" = "SP.POP.TOTL",
                            "gdp" = "NY.GDP.MKTP.CD",
                            "gdp_growth" = "NY.GDP.MKTP.KD.ZG",
                            "inflation" = "FP.CPI.TOTL.ZG",
                            "debt" = "GC.DOD.TOTL.GD.ZS",
                            "unemployment" = "SL.UEM.TOTL.ZS"), 
              #country = c('FR','US'), # here you can specify some countries
              extra = TRUE,
              start = 1960, 
              end = 2023) |>
  mutate(across(everything(), as.vector)) |>
  select(-status, -lending, -iso2c, -iso3c)
wb_data <- wb_raw |> filter(country %in% c("France", "United States")) |> arrange(country, year)
wb_eu <- wb_raw |> filter(country %in% c("Spain", "Italy", "Poland", "Slovenia")) |> arrange(country, year)

Below, we provide a snapshot of the data.

head(wb_data |> select(-region))
country year lastupdated gdp_per_capita population gdp gdp_growth inflation debt unemployment capital longitude latitude income
France 1960 2024-06-28 11169.65 46649927 62225478001 NA 4.139936 NA NA Paris 2.35097 48.8566 High income
France 1961 2024-06-28 11598.68 47161641 67461644222 4.980112 2.400461 NA NA Paris 2.35097 48.8566 High income
France 1962 2024-06-28 12257.76 47679792 75607529810 6.843470 5.331280 NA NA Paris 2.35097 48.8566 High income
France 1963 2024-06-28 12884.02 48189939 84759195106 6.233680 4.999153 NA NA Paris 2.35097 48.8566 High income
France 1964 2024-06-28 13587.67 48733997 94007851047 6.652100 3.211192 NA NA Paris 2.35097 48.8566 High income
France 1965 2024-06-28 14089.58 49282756 101537248148 4.861508 2.703105 NA NA Paris 2.35097 48.8566 High income

As usual, there are some missing points (NAs). Several causes can explain missing data. Either the country did not compute (or want to compute/disclose) particular indicators, or the database simply does not include it. Sometimes, it may be necessary to resort to several sources and join them.

2.1 Gross domestic product

2.1.1 Definitions

Surprisingly, there are several ways to evaluate the amount of goods and services produced within a country in a given year. We provide the definition used by the World Bank: “GDP is the sum of gross value added by all resident producers in the economy plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources”. As we will see later, there are several ways to compute the GDP, depending on the focus (production, income, expenditure).

The international standard for measuring GDP is contained in the System of National Accounts, 1993, compiled by the International Monetary Fund, the European Commission, the Organization for Economic Cooperation and Development, the United Nations, and the World Bank.

The baseline values reported for GDP are measured in the prices of a particular year. But current price series are influenced by the effects of inflation (see below in Section 2.2)… hence it is possible to correct this - in which case the series becomes “constant” in prices of a given year (e.g., 2010).

2.1.2 Examples

Let’s visualize the time-series of GDP per capita, this is usually the proxy for how rich the average citizen is - and is used to compared wealth (or well-being, loosely speaking) of citizens across the world. We can of course point to other indicators, like happiness, though they are out of the scope of the present course. The French statistical administration even introduced the idea of “subjective GDP” (see also this report).

Below, code snippets are shown in the body of the text, while visual output is presented in the right margin.

g <- wb_data |>
  mutate(gdp_per_capita = round(gdp_per_capita)) |>
  ggplot(aes(x = year, y = gdp_per_capita, color = country)) +
  geom_line() + theme_classic() +
  theme(axis.title = element_blank(),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("GDP per capita") +
  scale_color_manual(values = c("#22D4A3", "#000000"))
ggplotly(g) |>
  layout(legend = list(orientation = "h", x = -0.2, y =-0.2))

It seems the divide between the US and France has slowly but steadily accelerated since 1990. Investments, R&D spending (innovation & technology), as well as higher energy costs are potential explanations. Other reasons: a higher number of hours worked in the US, and the relative strength of the dollar (which fluctuates). For raw GDP, population trends are also important.

In Eastern Europe, GDP per capita has been catching up that of countries of Southern Europe since ~2010.

wb_eu |>
  mutate(gdp_per_capita = round(gdp_per_capita)) |>
  ggplot(aes(x = year, y = gdp_per_capita, color = country)) +
  geom_line() + theme_classic() +
  theme(axis.title = element_blank(),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("GDP per capita") +
  scale_color_observable()

But what about GDP growth?… \[\Delta GDP_t=\frac{GDP_t-GDP_{t-1}}{GDP_{t-1}}.\] (from one period - year - to the other).

wb_data |>
  mutate(gdp_growth = round(gdp_growth, 2)) |>
  ggplot(aes(x = year, y = gdp_growth, fill = country)) +
  geom_col(position = "dodge") + theme_classic() +
  theme(axis.title = element_blank(),
        legend.position = c(0.5,0.2),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("GDP growth (%)") +
  scale_fill_manual(values = c("#22D4A3", "#000000"))

In the recent period (1980 onwards), US figures are consistently above those of France. The US economy (as measured by GDP) has thus increased faster than France’s. This could already be seen in the preceding plot.

2.1.3 The cross-section of countries

What kind of differences exist between countries in terms of GDP/capita?

wb_raw |>
  filter(year == 2020, income != "Aggregates") |>
  mutate(gdp_per_capita = round(gdp_per_capita)) |>
  ggplot(aes(y = reorder(country, gdp_per_capita), x = gdp_per_capita)) + geom_col() +
  theme(axis.text.y = element_blank(), axis.title.y = element_blank()) + xlab("GDP per capita") + 
  annotate("text", label = "this is Monaco", y = "Monaco", x = 150000, size = 3, vjust = 1.2) + 
  annotate("text", label = "this is Niger", y = "Niger", x = 15000, size = 3, vjust = 0.5)

In 2020, the discrepancy is between Monaco (160k USD) and Niger (0.5k USD), so a gap between 1 and 300 roughly!

Who are the rich countries?

wb_raw |>
  filter(year == 2020, income != "Aggregates", gdp_per_capita > 50000) |>
  mutate(gdp_per_capita = round(gdp_per_capita)) |>
  ggplot(aes(y = reorder(country, gdp_per_capita), x = gdp_per_capita)) + geom_col(fill = "#2299FF") +
  theme_classic() + 
  theme(axis.title.y = element_blank()) + xlab("GDP per capita") 

A brief look at human development index (from the United Nations) that embeds other criteria:

We fetch data from the open-numbers repository on Github (managed by gapminder).

url <- "https://raw.githubusercontent.com/open-numbers/ddf--gapminder--systema_globalis/master/countries-etc-datapoints/ddf--datapoints--hdi_human_development_index--by--geo--time.csv"
hdi <- read_csv(url)
colnames(hdi) <- c("country", "year", "hdi")

hdi |>
  filter(country %in% c("fra", "usa")) |>
  ggplot(aes(x = year, y = hdi, color = country)) +
  geom_line() + theme_classic() +
  theme(axis.title = element_blank(),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("Human Development Index") +
  scale_color_manual(values = c("#22D4A3", "#000000"))

Money does not buy everything it seems… and France is catching up, despite lower GDP per capita in the recent period.

Across countries.

hdi |> 
  filter(year == 2021) |>
  arrange(desc(hdi)) |>
  head(10)
country year hdi
che 2021 0.962
nor 2021 0.961
isl 2021 0.959
hkg 2021 0.952
aus 2021 0.951
dnk 2021 0.948
swe 2021 0.947
irl 2021 0.945
deu 2021 0.942
nld 2021 0.941

2.2 Inflation

2.2.1 Definition

Now, let us move on to another important topic: the evolution of prices.

It is critical to maintain inflation to relatively low levels (e.g., 2%). Hyperinflation has devastating effects for a country (one notable case is Germany in the 1920s - but Argentina nowadays is another example). This is so important that in Europe, the primary mandate (objective) of the European Central Bank (ECB) is to control inflation, 2% being the usual target.
In the US, the tone is the same:

In conducting monetary policy, we will remain highly focused on fostering as strong a labor market as possible for the benefit of all Americans. And we will steadfastly seek to achieve a 2 percent inflation rate over time.

Federal Reserve Board (Fed) Chair Jerome Powell in his Aug. 27, 2020 speech.

But how is inflation computed? The calculation rests on the notion of a representative basket that encompasses the goods and services consumed by the average citizen of a country. The price of items (bread, apples, microwave oven, cars, cinema ticket, etc.) is recorded from various sources (across supermarket chains, but also from online stores). Then, the basket price is computed as a weighted average of all of its elements (this is sometimes referred to the Consumer Price Index - CPI). This is usually done every month, hence data is quite granular. Inflation is then the increase of the CPI compared to its value 12 months earlier.

2.2.2 Illustration

The horizontal grey line marks the 2% target (upper bound). It was quite well met between 1990 and 2020.

wb_data |>
  ggplot(aes(x = year, y = inflation, fill = country)) +
  geom_col(position = "dodge") + theme_classic() +
  theme(axis.title = element_blank(),
        legend.position = c(0.7,0.7),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("Inflation (%)") + geom_hline(yintercept = 2, color = "grey") + 
  annotate("text", label = "2% target", x = 2015, y = 4, color = "grey") + 
  scale_fill_manual(values = c("#22D4A3", "#000000"))

The values are annualized and they are in percents.
There appears to be a change. Before 1985, France had (much) higher inflation, but since then, it is the opposite.
We clearly see the post-2022 surge in high inflation.
From these series, we can reconstruct the CPI (usually, it’s done the other way around).

wb_data |>
  group_by(country) |>
  mutate(CPI = cumprod(1+inflation/100)) |>
  ggplot(aes(x = year, y = CPI, color = country)) + geom_line() +
  ggtitle("Customer Price index") +
  scale_color_manual(values = c("#22D4A3", "#000000")) + theme_classic() +
  theme(axis.title = element_blank(),
        legend.position = c(0.8,0.2),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) 

Prices have risen slightly faster in France, compared to the US - during the 1970-1990 decades. After that, trends are more parallel.

2.3 Unemployment

2.3.1 Definitions

For unemployment, there are some subtleties. Indeed, the World Bank proposes two estimates:

The French INSEE follows the ILO guidelines for instance. Someone is considered unemployed if the following criteria are verified. This person

  • is aged 15 years or over;
  • is without work;
  • has actively taken steps to seek work over the last four weeks or has found a job that begins in less than 3 months;
  • is available for work in the next two weeks

Employment starts when a person has done at least one hour’s paid work (including short contracts or partial work). The unemployment rate is: \[U = \frac{\# \text{unemployed}}{\# \text{employed} + \#\text{unemployed}}\]

The denominator is the size of the active workforce (who are in fact potentially active). Inactive people are for instance children or retired citizens. Estimates are produced thanks to Labour Force Surveys of 20 questions - conducted every quarter in France (sample size ~100k+). This is done continuously, with rolling “reference weeks”.

For comparison purposes, we stick to the ILO definition, but in this case, the data starts in 1991 only.

2.3.2 Examples

g <- wb_data |>
  na.omit() |>
  ggplot(aes(x = year, y = unemployment, color = country)) + geom_line() +
  theme_classic() + 
  theme(axis.title = element_blank(),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) + 
  ggtitle("Unemployment (%)") +
  scale_color_manual(values = c("#22D4A3", "#000000"))
ggplotly(g) |>
  layout(legend = list(orientation = "h", x = -0.2, y =-0.2))

There are pronounced fluctuations of the unemployment rate. Especially for the US, for which the job market is more “fluid”: jobs are more easily created and destroyed there, compared to France where it’s harder to lay off - and hence employers are more careful when hiring. The average value is again to the advantage of the US… (it is cutomary to consider that lower unemployment is better, but precarious jobs are also more widespread in the US).

2.4 Debt

2.4.1 Definition

Central governments use debt instruments (e.g., bonds) to access financial markets and capital. This is usually because their budgets is in deficit. Note that some data providers sometimes also provide a field called General Government Debt: in this case, local debts from cities, regions or states is also included in the totals. To keep numbers to reasonable levels, and to compare countries, the total debt levels are scaled by GDP.

Let’s have a look at a sample from the French debt:

2.4.2 Snapshot of data

wb_data |>
  filter(year > 1985) |>
  ggplot(aes(x = year, y = debt, fill = country)) +
  geom_hline(yintercept = 100, color = "grey") +
  geom_col(position = "dodge") + theme_classic() +
  theme(axis.title = element_blank(),
        legend.position = c(0.3, 0.7),
        title = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  ggtitle("Debt (% of GDP)") + 
  scale_fill_manual(values = c("#22D4A3", "#000000"))

We see the data is more recent here.
A natural threshold is 100%: when total debt is equal to national output.
The trend is clearly upward, which raises the question of the sustainability of ever growing debt. For now, it still holds, but for how long?

3 Bottom line

It is not easy to explain each one of this concepts alone (and the corresponding series). But the joint (and possibly causal) relationships across countries and between notions are very hard to rationalize!

Standard models try to explain sustained growth, but often fail to do so. This is what we will see/cover in the next sessions.

In short: we have seen the data (empirical salient facts), we will then cover theory.