2  UK Economic Data

The United Kingdom has some of the best-documented and most accessible economic data in the world. Four institutions publish the bulk of it, and each has a dedicated R package.

This chapter walks through pulling, cleaning, and combining data from the ONS, Bank of England, HMRC, and OBR — the building blocks of any UK macro analysis. By the end, you will have a single merged dataset of the UK’s key macroeconomic indicators, ready for charting or modelling.

2.1 The Office for National Statistics

library(ons)

The ONS is the UK’s national statistical institute, established in 1996 but tracing its lineage back to the General Register Office of 1837. It is responsible for producing the UK’s official measures of economic activity, prices, and the labour market. If you have ever seen a GDP growth figure, an inflation number, or an unemployment rate quoted for the UK, it almost certainly originated at the ONS.

The ONS publishes data through a combination of statistical bulletins (PDFs and web pages) and downloadable datasets. Under the hood, each time series has a four-character identifier called a CDID — for example, IHYQ is quarterly real GDP. The ons package handles the CDID lookup and CSV parsing for you; the convenience functions return tidy data frames with date and value columns.

One thing to be aware of: the ONS revises its data constantly. The first estimate of quarterly GDP is published roughly 40 days after the quarter ends, but it is then revised in the second estimate (roughly 70 days), the quarterly national accounts (roughly 90 days), and annual Blue Book revisions that can change figures going back years. This matters for real-time analysis — the GDP figure you download today for Q3 2023 may differ from what was available in October 2023. Chapter ?sec-time-series-essentials discusses data vintages in more detail.

2.1.1 GDP

GDP — gross domestic product — is the broadest measure of economic activity. The ONS publishes quarterly GDP in chained volume measures (i.e., adjusted for inflation) and in current prices. The ons_gdp() function returns the headline quarterly real GDP index.

gdp <- ons_gdp(measure = "level")
ℹ Fetching GDP (level)
✔ Fetching GDP (level) [58ms]
head(gdp)
        date  value
1 1955-01-01 145457
2 1955-04-01 145551
3 1955-07-01 147995
4 1955-10-01 147119
5 1956-01-01 148955
6 1956-04-01 148835
#>         date  value
#> 1 1955-01-01 145457
#> 2 1955-04-01 145551
#> 3 1955-07-01 147995
#> 4 1955-10-01 147119
#> 5 1956-01-01 148955
#> 6 1956-04-01 148835

The series goes back to 1955 and is indexed (100 = 2022). To calculate quarter-on-quarter growth rates, you can use base R or dplyr:

gdp$growth <- c(NA, diff(gdp$value) / head(gdp$value, -1) * 100)
tail(gdp)
          date  value     growth
279 2024-07-01 696853 0.22623979
280 2024-10-01 698780 0.27652891
281 2025-01-01 703373 0.65728842
282 2025-04-01 704798 0.20259521
283 2025-07-01 705187 0.05519312
284 2025-10-01 705571 0.05445364

The ONS also publishes a monthly GDP estimate, which is useful for nowcasting and for pinpointing turning points more precisely than quarterly data allow:

monthly_gdp <- ons_monthly_gdp()
ℹ Fetching monthly GDP
✔ Fetching monthly GDP [89ms]
head(monthly_gdp)
        date value
1 1997-01-01  61.6
2 1997-02-01  61.9
3 1997-03-01  61.8
4 1997-04-01  62.6
5 1997-05-01  62.1
6 1997-06-01  62.5

2.1.2 Inflation

The Consumer Prices Index (CPI) is the UK’s headline measure of inflation and the target variable for the Bank of England’s Monetary Policy Committee. The MPC targets 2% annual CPI inflation. ons_cpi() returns the annual percentage change in CPI:

cpi <- ons_cpi()
ℹ Fetching CPI (rate)
✔ Fetching CPI (rate) [60ms]
head(cpi)
        date value
1 1989-01-01   4.9
2 1989-02-01   5.0
3 1989-03-01   5.0
4 1989-04-01   5.3
5 1989-05-01   5.3
6 1989-06-01   5.2
#>         date value
#> 1 1989-01-01   5.7
#> 2 1989-02-01   5.8
#> 3 1989-03-01   5.9
#> 4 1989-04-01   5.6
#> 5 1989-05-01   5.4
#> 6 1989-06-01   5.2

Note that CPI data is monthly. The annual rate — the percentage change compared with the same month a year earlier — is the figure that makes headlines and that the MPC targets. When inflation hit 11.1% in October 2022, this was the CPI annual rate.

2.1.3 The labour market

The labour market data from the ONS covers three key rates: unemployment, employment, and economic inactivity. Together they describe the entire working-age population. The unemployment rate gets the most attention, but inactivity — people who are neither working nor looking for work — has become increasingly important since the pandemic, as a rise in long-term sickness has pushed inactivity well above pre-COVID levels.

unemp <- ons_unemployment()
ℹ Fetching unemployment rate
✔ Fetching unemployment rate [79ms]
head(unemp)
        date value
1 1971-02-01   3.8
2 1971-03-01   3.9
3 1971-04-01   4.0
4 1971-05-01   4.1
5 1971-06-01   4.1
6 1971-07-01   4.2
#>         date value
#> 1 1971-03-01   3.6
#> 2 1971-06-01   3.8
#> 3 1971-09-01   3.9
#> 4 1971-12-01   3.9
#> 5 1972-03-01   4.0
#> 6 1972-06-01   3.9

The unemployment rate is reported as a three-month rolling average — the figure for March 2024 covers the January-to-March period. This smooths out monthly noise but means the series lags reality by about six weeks.

Wages data is equally important for monetary policy, since wage growth feeds into service-sector inflation. The ons_wages() function returns average weekly earnings growth:

wages <- ons_wages(measure = "growth")
ℹ Fetching average weekly earnings (growth)
✔ Fetching average weekly earnings (growth) [33ms]
head(wages)
        date value
1 2001-03-01   6.1
2 2001-04-01   6.2
3 2001-05-01   5.1
4 2001-06-01   5.5
5 2001-07-01   5.2
6 2001-08-01   5.3
#>         date value
#> 1 2001-03-01   6.1
#> 2 2001-04-01   6.2
#> 3 2001-05-01   5.1
#> 4 2001-06-01   5.5
#> 5 2001-07-01   5.2
#> 6 2001-08-01   5.3

The MPC watches this series closely. During 2023-24, wage growth running at 7-8% was a key reason the Committee held rates at 5.25% for an extended period — service-sector firms pass wage costs through to prices, and wage growth at that level is inconsistent with 2% inflation.

2.2 The Bank of England

library(boe)

Attaching package: 'boe'
The following object is masked from 'package:ons':

    clear_cache

The Bank of England is the UK’s central bank, responsible for monetary policy, financial stability, and the regulation of banks and insurers. For macroeconomists, its most important data publications are the policy rate (Bank Rate), money market rates, the gilt yield curve, and lending data.

Where the ONS tells you what the economy did, the Bank of England’s data tells you what monetary conditions are. Bank Rate is the lever; gilt yields, mortgage rates, and exchange rates are the transmission mechanism through which it affects the real economy.

2.2.1 Bank Rate

Bank Rate is the interest rate that the Bank of England pays on reserves held by commercial banks overnight. It is the anchor for the entire UK interest rate structure. When the MPC raises Bank Rate, mortgage rates rise, corporate borrowing costs increase, and the exchange rate typically appreciates — all of which slow the economy and reduce inflation.

bank_rate <- boe_bank_rate()
ℹ Using cached data
✔ Using cached data [3ms]
head(bank_rate)
        date rate_pct
1 1975-01-02     11.5
2 1975-01-03     11.5
3 1975-01-06     11.5
4 1975-01-07     11.5
5 1975-01-08     11.5
6 1975-01-09     11.5
#>         date value
#> 1 1694-08-01  6.00
#> 2 1694-09-01  6.00
#> 3 1694-10-01  6.00
#> 4 1694-11-01  6.00
#> 5 1694-12-01  6.00
#> 6 1695-01-01  6.00

The series goes back to 1694, making it one of the longest continuous financial time series in the world. For most practical analysis you will want to filter to a more recent period:

bank_rate_recent <- boe_bank_rate(from = "2000-01-01")
ℹ Using cached data
✔ Using cached data [3ms]

2.2.2 The gilt yield curve

The yield curve — the relationship between interest rates and maturity — is one of the most information-rich objects in financial markets. A normal yield curve slopes upward (longer-term rates are higher than short-term rates); an inverted yield curve (short rates above long rates) has historically been a reliable predictor of recession.

gilts <- boe_yield_curve(from = "2020-01-01")
ℹ Using cached data
✔ Using cached data [3ms]
head(gilts)
        date maturity yield_pct
1 2020-01-02     10yr    0.8523
2 2020-01-02     20yr    1.1599
3 2020-01-02      5yr    0.5519
4 2020-01-03     10yr    0.8094
5 2020-01-03     20yr    1.0989
6 2020-01-03      5yr    0.5349

The Bank of England publishes both nominal and real (inflation-linked) yield curves. The difference between them — the breakeven inflation rate — gives you the market’s expectation of future inflation. This is a key input for monetary policy analysis and is covered in Chapter 8.

2.2.3 Mortgage rates

Mortgage rates matter because housing is the main transmission channel for monetary policy in the UK. Most UK mortgages are fixed for two or five years, so changes in Bank Rate feed through to household budgets with a lag as borrowers refinance. The boe_mortgage_rates() function provides average quoted mortgage rates by type:

mortgages <- boe_mortgage_rates()
ℹ Using cached data
✔ Using cached data [3ms]
head(mortgages)
        date      type rate_pct
1 1995-01-31 2yr_fixed     8.13
2 1995-02-28 2yr_fixed     8.38
3 1995-03-31 2yr_fixed     8.08
4 1995-04-30 2yr_fixed     8.29
5 1995-05-31 2yr_fixed     8.22
6 1995-06-30 2yr_fixed     7.94

The spread between mortgage rates and Bank Rate is itself informative — when it widens, banks are tightening lending conditions beyond what the policy rate alone would imply.

2.3 HM Revenue & Customs

library(hmrc)

Attaching package: 'hmrc'
The following object is masked from 'package:boe':

    clear_cache
The following object is masked from 'package:ons':

    clear_cache

HMRC is the UK’s tax authority. From a macroeconomic perspective, its most valuable publication is monthly tax receipt data. Tax receipts are a real-time read on economic activity, because they respond immediately to changes in employment (income tax and NICs), consumer spending (VAT), corporate profits (corporation tax), and the housing market (stamp duty).

Unlike ONS data, which is estimated from surveys and subject to revision, tax receipts are administrative data — they reflect actual money collected by the government. This makes them useful for cross-checking ONS estimates and for nowcasting exercises.

2.3.1 Tax receipts

The get_tax_receipts() function returns monthly receipts for all major tax heads, or you can filter to a specific tax:

receipts <- get_tax_receipts()
ℹ Resolving download URL from GOV.UK Content API
✔ Resolving download URL from GOV.UK Content API [142ms]
ℹ Using cached file
✔ Using cached file [7ms]
ℹ Parsing data
New names:
✔ Parsing data [286ms]

• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
• `` -> `...12`
• `` -> `...13`
• `` -> `...14`
• `` -> `...15`
• `` -> `...16`
• `` -> `...17`
• `` -> `...18`
• `` -> `...19`
• `` -> `...20`
• `` -> `...21`
• `` -> `...22`
• `` -> `...23`
• `` -> `...24`
• `` -> `...25`
• `` -> `...26`
• `` -> `...27`
• `` -> `...28`
• `` -> `...29`
• `` -> `...30`
• `` -> `...31`
• `` -> `...32`
• `` -> `...33`
• `` -> `...34`
• `` -> `...35`
• `` -> `...36`
• `` -> `...37`
• `` -> `...38`
• `` -> `...39`
• `` -> `...40`
• `` -> `...41`
• `` -> `...42`
• `` -> `...43`
• `` -> `...44`
• `` -> `...45`
• `` -> `...46`
• `` -> `...47`
head(receipts)
        date        tax_head     description receipts_gbp_m
1 2016-04-01 aggregates_levy Aggregates Levy             40
2 2016-05-01 aggregates_levy Aggregates Levy             22
3 2016-06-01 aggregates_levy Aggregates Levy             20
4 2016-07-01 aggregates_levy Aggregates Levy             51
5 2016-08-01 aggregates_levy Aggregates Levy             27
6 2016-09-01 aggregates_levy Aggregates Levy             21

You can see which tax heads are available using list_tax_heads():

list_tax_heads()
                             tax_head
1                      total_receipts
2                          income_tax
3                   capital_gains_tax
4                     inheritance_tax
5                 apprenticeship_levy
6                          nics_total
7                       nics_employer
8                       nics_employee
9                  nics_self_employed
10                                vat
11                    corporation_tax
12                          bank_levy
13                     bank_surcharge
14                   bank_payroll_tax
15               diverted_profits_tax
16               digital_services_tax
17 residential_property_developer_tax
18                energy_profits_levy
19        electricity_generators_levy
20                economic_crime_levy
21              petroleum_revenue_tax
22                          fuel_duty
23                  stamp_duty_shares
24                               sdlt
25                               ated
26                       tobacco_duty
27                       spirits_duty
28                          beer_duty
29                          wine_duty
30                         cider_duty
31                    gambling_duties
32                 air_passenger_duty
33              insurance_premium_tax
34                       landfill_tax
35                climate_change_levy
36                    aggregates_levy
37                   soft_drinks_levy
38              plastic_packaging_tax
39                     customs_duties
40                      miscellaneous
41                          penalties
                                                      description    category
1                                             Total HMRC receipts       total
2                           Income Tax (PAYE and Self Assessment)      income
3                                               Capital Gains Tax      income
4                                                 Inheritance Tax      income
5                                             Apprenticeship Levy      income
6                  National Insurance Contributions (all classes)        nics
7      National Insurance Contributions - employer (Class 1 PAYE)        nics
8      National Insurance Contributions - employee (Class 1 PAYE)        nics
9  National Insurance Contributions - self-employed (Class 2 & 4)        nics
10                                                Value Added Tax consumption
11                                      Corporation Tax (onshore)      income
12                                                      Bank Levy      income
13                                                 Bank Surcharge      income
14                                               Bank Payroll Tax      income
15                                           Diverted Profits Tax      income
16                                           Digital Services Tax      income
17                             Residential Property Developer Tax      income
18                                            Energy Profits Levy      income
19                                    Electricity Generators Levy      income
20                                            Economic Crime Levy      income
21                                          Petroleum Revenue Tax      income
22                             Hydrocarbon Oil Duties (Fuel Duty) consumption
23                                Stamp Duty Reserve Tax (shares)    property
24                                            Stamp Duty Land Tax    property
25                              Annual Tax on Enveloped Dwellings    property
26                                                 Tobacco Duties consumption
27                                                 Spirits Duties consumption
28                                                    Beer Duties consumption
29                                      Wine and Made-Wine Duties consumption
30                                         Cider and Perry Duties consumption
31                                      Betting and Gaming Duties consumption
32                                             Air Passenger Duty consumption
33                                          Insurance Premium Tax consumption
34                                                   Landfill Tax environment
35                                            Climate Change Levy environment
36                                                Aggregates Levy environment
37                                      Soft Drinks Industry Levy consumption
38                                          Plastic Packaging Tax consumption
39                                                 Customs Duties       other
40                                         Miscellaneous receipts       other
41                                         Penalties and interest       other
   available_from
1            2016
2            2016
3            2016
4            2016
5            2017
6            2016
7            2016
8            2016
9            2016
10           2016
11           2016
12           2016
13           2016
14           2010
15           2016
16           2020
17           2022
18           2022
19           2023
20           2023
21           2016
22           2016
23           2016
24           2016
25           2016
26           2016
27           2016
28           2016
29           2016
30           2016
31           2016
32           2016
33           2016
34           2016
35           2016
36           2016
37           2018
38           2022
39           2016
40           2016
41           2016

To pull a specific tax — for example, VAT receipts:

vat <- get_tax_receipts(tax = "vat")
ℹ Resolving download URL from GOV.UK Content API
✔ Resolving download URL from GOV.UK Content API [27ms]
ℹ Using cached file
✔ Using cached file [6ms]
ℹ Parsing data
New names:
✔ Parsing data [180ms]

• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
• `` -> `...12`
• `` -> `...13`
• `` -> `...14`
• `` -> `...15`
• `` -> `...16`
• `` -> `...17`
• `` -> `...18`
• `` -> `...19`
• `` -> `...20`
• `` -> `...21`
• `` -> `...22`
• `` -> `...23`
• `` -> `...24`
• `` -> `...25`
• `` -> `...26`
• `` -> `...27`
• `` -> `...28`
• `` -> `...29`
• `` -> `...30`
• `` -> `...31`
• `` -> `...32`
• `` -> `...33`
• `` -> `...34`
• `` -> `...35`
• `` -> `...36`
• `` -> `...37`
• `` -> `...38`
• `` -> `...39`
• `` -> `...40`
• `` -> `...41`
• `` -> `...42`
• `` -> `...43`
• `` -> `...44`
• `` -> `...45`
• `` -> `...46`
• `` -> `...47`
head(vat)
           date tax_head     description receipts_gbp_m
4603 2016-04-01      vat Value Added Tax          11087
4604 2016-05-01      vat Value Added Tax          10957
4605 2016-06-01      vat Value Added Tax           6058
4606 2016-07-01      vat Value Added Tax          12227
4607 2016-08-01      vat Value Added Tax          10789
4608 2016-09-01      vat Value Added Tax           6486

2.3.2 Corporation tax and stamp duty

For more granular data on specific taxes, the hmrc package provides dedicated functions. Corporation tax receipts give a read on corporate profitability:

corp_tax <- get_corporation_tax()
ℹ Resolving download URL from GOV.UK Content API
✔ Resolving download URL from GOV.UK Content API [58ms]
ℹ Using cached file
✔ Using cached file [4ms]
ℹ Parsing data
New names:
✔ Parsing data [49ms]

• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
head(corp_tax)
  tax_year                type         description receipts_gbp_m
1  2019-20 all_corporate_taxes All Corporate Taxes          66025
2  2020-21 all_corporate_taxes All Corporate Taxes          54238
3  2021-22 all_corporate_taxes All Corporate Taxes          67548
4  2022-23 all_corporate_taxes All Corporate Taxes          84595
5  2023-24 all_corporate_taxes All Corporate Taxes          93675
6  2024-25 all_corporate_taxes All Corporate Taxes          97161

Stamp duty land tax (SDLT) receipts track the housing market. During housing booms, SDLT receipts surge; during downturns, they collapse. The sensitivity of this tax to housing transactions makes it a useful high-frequency housing indicator:

sdlt <- get_stamp_duty()
ℹ Resolving download URL from GOV.UK Content API
✔ Resolving download URL from GOV.UK Content API [48ms]
ℹ Using cached file
✔ Using cached file [3ms]
ℹ Parsing data
New names:
✔ Parsing data [97ms]

• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
head(sdlt)
  tax_year        type        description receipts_gbp_m
1  2003-04 sdlt_leases SDLT on new leases            405
2  2004-05 sdlt_leases SDLT on new leases            945
3  2005-06 sdlt_leases SDLT on new leases            810
4  2006-07 sdlt_leases SDLT on new leases           1330
5  2007-08 sdlt_leases SDLT on new leases            915
6  2008-09 sdlt_leases SDLT on new leases            595

2.3.3 Property transactions

HMRC also publishes monthly counts of property transactions — a direct measure of housing market activity that complements the ONS house price index:

transactions <- get_property_transactions()
ℹ Resolving download URL from GOV.UK Content API
✔ Resolving download URL from GOV.UK Content API [50ms]
ℹ Using cached file
✔ Using cached file [4ms]
ℹ Parsing data
New names:
New names:
✔ Parsing data [112ms]

• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
head(transactions)
        date  nation            type transactions
1 2005-04-01 england non_residential         9200
2 2005-05-01 england non_residential         8620
3 2005-06-01 england non_residential         9960
4 2005-07-01 england non_residential        10120
5 2005-08-01 england non_residential         9100
6 2005-09-01 england non_residential         9410

2.4 The Office for Budget Responsibility

library(obr)

Attaching package: 'obr'
The following object is masked from 'package:hmrc':

    clear_cache
The following object is masked from 'package:boe':

    clear_cache
The following object is masked from 'package:ons':

    clear_cache

The OBR is the UK’s independent fiscal watchdog, created in 2010 to provide impartial analysis of the public finances. It produces five-year economic and fiscal forecasts at each Budget or fiscal event, certifying whether the government is on track to meet its fiscal rules. The OBR’s forecasts are the official projections used in all government planning.

For macroeconomists, the OBR is valuable for two reasons. First, its Public Finances Databank contains decades of historical fiscal data — government receipts, expenditure, borrowing, and debt — in a clean, consistent format. Second, its Economic and Fiscal Outlook (EFO) publications contain forecast vintages that allow you to compare successive forecasts and assess how the fiscal position has changed.

2.4.1 Public finances

The get_public_finances() function returns the full public finances dataset. For specific fiscal aggregates, there are convenience functions:

# Public sector net borrowing (the deficit)
psnb <- get_psnb()
ℹ Loading from cache. Use `refresh = TRUE` to re-download.
head(psnb)
     year psnb_bn
1 1946-47   0.629
2 1947-48   0.079
3 1948-49  -0.496
4 1949-50  -0.587
5 1950-51  -0.466
6 1951-52  -0.069
# Public sector net debt
psnd <- get_psnd()
ℹ Loading from cache. Use `refresh = TRUE` to re-download.
head(psnd)
     year psnd_bn
1 1974-75    52.1
2 1975-76    64.7
3 1976-77    73.6
4 1977-78    79.5
5 1978-79    88.6
6 1979-80    98.2
# Government receipts and expenditure
receipts <- get_receipts()
ℹ Loading from cache. Use `refresh = TRUE` to re-download.
expenditure <- get_expenditure()
ℹ Loading from cache. Use `refresh = TRUE` to re-download.

Public sector net borrowing (PSNB) — the government’s deficit — is the single most-watched fiscal aggregate. It measures the gap between what the government spends and what it collects in tax revenue. When PSNB is positive, the government is borrowing; the cumulated stock of past borrowing is public sector net debt (PSND).

2.4.2 Fiscal forecasts

The OBR’s forecast vintages let you see how expectations have changed over time. You can retrieve forecasts for specific fiscal series and compare the OBR’s projections at different fiscal events:

# See what forecast series are available
list_forecast_series()
            series sheet                               description
1             PSNB £PSNB         Public sector net borrowing (£bn)
2         PSNB_pct  PSNB    Public sector net borrowing (% of GDP)
3             PSND  PSND         Public sector net debt (% of GDP)
4         receipts £PSCR      Public sector current receipts (£bn)
5     receipts_pct  PSCR Public sector current receipts (% of GDP)
6      expenditure  £TME           Total managed expenditure (£bn)
7  expenditure_pct   TME      Total managed expenditure (% of GDP)
8              GDP  NGDP                    Nominal GDP growth (%)
9         real_GDP UKGDP                       Real GDP growth (%)
10             CPI   CPI                         CPI inflation (%)
# Get PSNB forecasts across all available EFO vintages
psnb_forecasts <- get_forecasts(series = "PSNB")
ℹ Loading from cache. Use `refresh = TRUE` to re-download.
head(psnb_forecasts)
    series forecast_date fiscal_year value
1     PSNB    April 1970     1970-71  -0.2
2     PSNB    March 1971     1970-71   0.6
106   PSNB    March 1971     1971-72   1.2
107   PSNB    March 1972     1971-72   1.3
211   PSNB    March 1972     1972-73   3.4
212   PSNB    March 1973     1972-73   2.9

Comparing forecast vintages is a powerful analytical tool. If the OBR’s borrowing forecast has risen by 20 billion pounds between two fiscal events, you can decompose the change into economic determinants (weaker growth, higher inflation) and policy measures (tax cuts, spending increases). This is exactly the analysis that fiscal journalists and Treasury economists do on Budget day.

2.4.3 Welfare spending

The OBR also publishes detailed breakdowns of welfare spending, which is the largest single component of government expenditure:

welfare <- get_welfare_spending()
ℹ Loading from cache. Use `refresh = TRUE` to re-download.
head(welfare)
     year                                   series     value
1 1978-79 Working-age incapacity benefits spending 0.8916853
2 1979-80 Working-age incapacity benefits spending 0.8109902
3 1980-81 Working-age incapacity benefits spending 0.7620921
4 1981-82 Working-age incapacity benefits spending 0.7774238
5 1982-83 Working-age incapacity benefits spending 0.7563964
6 1983-84 Working-age incapacity benefits spending 0.6981748

2.5 Putting it together: a UK macro dataset

A common task in applied macro is to assemble a single dataset of key UK macro indicators — GDP growth, inflation, unemployment, and Bank Rate — for analysis or charting. This requires merging data from different sources, which means dealing with different frequencies and date formats.

The good news is that all of the packages used in this chapter return data frames with a date column of class Date, so merging is straightforward. The complication is frequency: GDP is quarterly, CPI and unemployment are monthly, and Bank Rate changes irregularly (it stays constant between MPC decisions).

Let us build a quarterly dataset step by step.

2.5.1 Step 1: Pull the raw data

library(ons)
library(boe)

gdp   <- ons_gdp(measure = "level")  # quarterly index
ℹ Fetching GDP (level)
✔ Fetching GDP (level) [43ms]
cpi   <- ons_cpi()           # monthly
ℹ Fetching CPI (rate)
✔ Fetching CPI (rate) [58ms]
unemp <- ons_unemployment()  # monthly (3-month rolling)
ℹ Fetching unemployment rate
✔ Fetching unemployment rate [79ms]
br    <- boe_bank_rate()     # irregular (changes at MPC meetings)
ℹ Using cached data
✔ Using cached data [3ms]

2.5.2 Step 2: Convert everything to quarterly frequency

For monthly series, we take the quarterly average — the mean of the three monthly values within each quarter. For Bank Rate, which is recorded whenever it changes, we also take the quarterly average (the mean rate prevailing during the quarter).


Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
# Helper: assign each date to the first day of its quarter
to_quarter <- function(d) {
  as.Date(paste0(format(d, "%Y-"),
                 sprintf("%02d", (as.numeric(format(d, "%m")) - 1) %/% 3 * 3 + 1),
                 "-01"))
}

# Quarterly CPI: average of the three monthly readings
cpi_q <- cpi |>
  mutate(quarter = to_quarter(date)) |>
  summarise(cpi = mean(value, na.rm = TRUE), .by = quarter) |>
  rename(date = quarter)

# Quarterly unemployment: average of the three monthly readings
unemp_q <- unemp |>
  mutate(quarter = to_quarter(date)) |>
  summarise(unemployment = mean(value, na.rm = TRUE), .by = quarter) |>
  rename(date = quarter)

# Quarterly Bank Rate: average over the quarter
# First expand to monthly, then average
br_monthly <- br |>
  arrange(date) |>
  mutate(month = as.Date(format(date, "%Y-%m-01")))

# For each month, the prevailing rate is the last change on or before that month
months <- data.frame(date = seq(min(br_monthly$month),
                                Sys.Date(),
                                by = "month"))

br_filled <- months |>
  left_join(br |> mutate(date = as.Date(format(date, "%Y-%m-01"))),
            by = "date") |>
  tidyr::fill(rate_pct, .direction = "down")

br_q <- br_filled |>
  mutate(quarter = to_quarter(date)) |>
  summarise(bank_rate = mean(rate_pct, na.rm = TRUE), .by = quarter) |>
  rename(date = quarter)

2.5.3 Step 3: Merge into a single data frame

Now we have four quarterly data frames, each with a date column. A series of left joins on date produces the final dataset:

# Prepare GDP with a cleaner column name
gdp_clean <- gdp |>
  select(date, gdp = value)

# Merge everything
uk_macro <- gdp_clean |>
  left_join(cpi_q, by = "date") |>
  left_join(unemp_q, by = "date") |>
  left_join(br_q, by = "date")

tail(uk_macro)
          date    gdp      cpi unemployment bank_rate
279 2024-07-01 696853 2.033333     4.233333  5.088462
280 2024-10-01 698780 2.466667     4.400000  4.855469
281 2025-01-01 703373 2.800000     4.500000  4.599206
282 2025-04-01 704798 3.500000     4.700000  4.348361
283 2025-07-01 705187 3.800000     4.966667  4.103846
284 2025-10-01 705571 3.400000     5.150000  3.968750
#>           date    gdp  cpi unemployment bank_rate
#> ...

2.5.4 Step 4: Calculate GDP growth

The GDP series is an index, not a growth rate. To get quarter-on-quarter growth:

uk_macro <- uk_macro |>
  mutate(gdp_growth = (gdp / lag(gdp) - 1) * 100)

2.5.5 Step 5: A quick chart

With all four series in one data frame, you can produce a multi-panel chart showing the state of the UK economy:

library(ggplot2)
library(tidyr)

uk_plot <- uk_macro |>
  filter(date >= as.Date("2000-01-01")) |>
  select(date, `GDP growth (%)` = gdp_growth,
         `CPI inflation (%)` = cpi,
         `Unemployment (%)` = unemployment,
         `Bank Rate (%)` = bank_rate) |>
  pivot_longer(-date, names_to = "series", values_to = "value")

ggplot(uk_plot, aes(x = date, y = value)) +
  geom_line(colour = "#1f77b4", linewidth = 0.6) +
  facet_wrap(~series, scales = "free_y", ncol = 2) +
  labs(title = "UK macroeconomic indicators",
       x = NULL, y = NULL,
       caption = "Sources: ONS, Bank of England") +
  theme_minimal(base_size = 11) +
  theme(strip.text = element_text(face = "bold"))

This gives you a dashboard-style view of the UK economy in about 40 lines of code. The same dataset serves as the starting point for the Phillips curve estimation in Chapter ?sec-inflation-phillips-curve and the VAR model in Chapter ?sec-var-models.

2.6 A note on data revisions

If you download GDP data today and again in three months, the numbers may differ — even for quarters that are years in the past. The ONS revises GDP in three stages: the first estimate (published about 40 days after the quarter ends), the second estimate (about 70 days), and the quarterly national accounts (about 90 days). Annual Blue Book revisions can change the entire historical series.

This is not a flaw in the data; it reflects genuine improvements in measurement as more information becomes available. But it matters for practitioners. If you are evaluating a forecast made in October 2023, you need to compare it against the GDP estimate that was available in October 2023, not today’s revised figure. The difference can be substantial — early GDP estimates have been revised by as much as a full percentage point.

For academic research and rigorous forecast evaluation, you need real-time data vintages. The ONS does not provide a convenient vintage database (unlike the Federal Reserve Bank of Philadelphia, which maintains a famous real-time dataset for the US). In practice, UK economists either save snapshots of data at regular intervals or use the OECD’s real-time database for cross-country comparisons. This is an area where careful data management — saving your downloaded data with timestamps — pays off.

2.7 Exercises

  1. Pull UK GDP data with ons_gdp() and calculate the quarter-on-quarter growth rate. In which quarter was growth weakest since 2010? (Hint: the answer involves the COVID pandemic, but check the data to be sure.)

  2. Download Bank Rate with boe_bank_rate() and CPI inflation with ons_cpi(). Merge them into a monthly dataset and plot both on the same chart using facets. What do you notice about the relationship between the two during 2021-23?

  3. Using hmrc::get_tax_receipts(), pull the latest tax receipts data. Which tax head generates the most annual revenue? Plot the monthly time series for the three largest tax heads on a single chart.

  4. Build the quarterly UK macro dataset described in Section 2.5. Extend it by adding wage growth from ons_wages(). Calculate the real wage growth rate (nominal wage growth minus CPI inflation). Plot real wage growth since 2008. When was the longest period of falling real wages?

  5. Pull PSNB forecasts from the OBR using obr::get_forecasts(series = "PSNB"). Plot the forecast paths from the three most recent fiscal events on a single chart. How has the borrowing outlook changed?