“It’s the inflation, stupid!”

Putting inflation in perspective historically and cross-sectionally by looking at data from the OECD data warehouse.
python
altair
visualisation
economy
Published

December 9, 2022

One of the major themes for the economic news cycle of 2022 has been inflation. To assess the scale and impact rising prices have had across the globe, it is interesting to look at the consumer price indices (CPI) for various countries. A consumer price index (CPI) measures the price of a weighted average market basket of consumer goods and services purchased by households. Changes in CPI track changes in prices over time. To put current inflation numbers into a historical perspective, it is interesting to look at a long-term time series of inflation.

OECD maintains an aggregated database of more than 50 national CPI indices in the OECD data warehouse. This includes long-term time series data for the USA (where OECD has data available going back to 1955) as well as an aggregate measure for all OECD countries (data available since 1970).

A long-term view on inflation

The inflation time series for the USA and OECD as a whole have a very similar dynamic and had their historical maximum in the late 70s/early 80s at a peak rate of ~15% year-on-year. For much of the last 50 years, however, inflation was in the range of 2 to 4 per cent.

Time series of US and OECD inflation

Code
import altair as alt
import pandas as pd

def get_from_oecd(sdmx_query):
    return pd.read_csv(
        f"https://stats.oecd.org/SDMX-JSON/data/{sdmx_query}"
    )

long_countries = ['USA', 'OECD']

cpi_long = get_from_oecd("PRICES_CPI/%s.CPALTT01.GY.M/all?startTime=1950&endTime=2022&contentType=csv" % "+".join(long_countries))
cpi_long['Value'] /= 100
cpi_long['TIME'] = pd.to_datetime(cpi_long.TIME)

cpi_long['Country'] = cpi_long['Country'].replace({'OECD - Total': 'OECD'})

selection = alt.selection_multi(fields=['Country'], bind='legend')

alt.Chart(cpi_long).mark_line().encode(
    x=alt.X('TIME:T', title=''),
    y=alt.Y('Value:Q', title='Inflation (YoY)', axis=alt.Axis(format="%")),
    color='Country:O',
    tooltip=['Country',
             alt.Tooltip('TIME', format='%b %Y', title='Date'),
             alt.Tooltip('Value', format=".1%", title='Inflation (YoY)')]
).transform_filter(
    selection
).add_selection(
    selection
).properties(
    width=550
)

Source: OECD (2022), Inflation (National CPI, % change vs. prior year, seasonally adjusted). doi: 10.1787/eee82e6e-en

Comparing inflation across countries

OECD aggregates national CPI data from a range of European and other developed as well as emerging market countries. It is interesting to compare the time series data across countries.

Cross-sectional inflation data for 44 European, other DM and EM countries

Code
import datetime

countries = ['AUS', 'AUT', 'BEL', 'CAN', 'CHL', 'COL', 'CRI', 'CZE', 'DNK',
             'EST', 'FIN', 'FRA', 'DEU', 'GRC', 'HUN', 'ISL', 'IRL', 'ISR',
             'ITA', 'JPN', 'KOR', 'LVA', 'LTU', 'LUX', 'MEX', 'NLD', 'NZL',
             'NOR', 'POL', 'PRT', 'SVK', 'SVN', 'ESP', 'SWE', 'CHE', 'TUR',
             'GBR', 'USA', 'EA19', 'EU27_2020', 'G-7', 'OECDE', 'G-20', 'OECD',
             'NMEC', 'ARG', 'BRA', 'CHN', 'IND', 'IDN', 'RUS', 'SAU', 'ZAF']

cpi = get_from_oecd("PRICES_CPI/%s.CPALTT01.GY.M/all?startTime=2012&endTime=2022&contentType=csv" % "+".join(countries))
cpi['Value'] /= 100
cpi['TIME'] = pd.to_datetime(cpi.TIME)

region_order = ['Europe', 'Other DM', 'Emerging Markets']

country_replacements = {
    "China (People's Republic of)": 'China',
    'Slovak Republic': 'Slovakia'
}

country_region_map = {
    'Austria': 'Europe',
    'Belgium': 'Europe',
    'Denmark': 'Europe',
    'Czech Republic': 'Europe',
    'Estonia': 'Europe',
    'Finland': 'Europe',
    'France': 'Europe',
    'Germany': 'Europe',
    'Greece': 'Europe',
    'Hungary': 'Europe',
    'Iceland': 'Europe',
    'Ireland': 'Europe',
    'Italy': 'Europe',
    'Latvia': 'Europe',
    'Lithuania': 'Europe',
    'Luxembourg': 'Europe',
    'Netherlands': 'Europe',
    'Norway': 'Europe',
    'Poland': 'Europe',
    'Portugal': 'Europe',
    'Slovakia': 'Europe',
    'Slovenia': 'Europe',
    'Spain': 'Europe',
    'Sweden': 'Europe',
    'Switzerland': 'Europe',
    'United Kingdom': 'Europe',
    
    'Canada': 'Other DM',
    'Israel': 'Other DM',
    'Japan': 'Other DM',
    'Korea': 'Other DM',
    'United States': 'Other DM',
    
    'Brazil': 'Emerging Markets',
    'Chile': 'Emerging Markets',
    'China': 'Emerging Markets',
    'Colombia': 'Emerging Markets',
    'India': 'Emerging Markets',
    'Indonesia': 'Emerging Markets',
    'Mexico': 'Emerging Markets',
    'Russia': 'Emerging Markets',
    'Saudi Arabia': 'Emerging Markets',
    'South Africa': 'Emerging Markets',
    
    # 'Argentina': 'Other',
    # 'Türkiye': 'Other',
    # 'Costa Rica': 'Other',
    
    # 'Euro area (19 countries)': 'Other',
    # 'European Union – 27 countries (from 01/02/2020)': 'Other',
    # 'G20': 'Other',
    # 'G7': 'Other',
    # 'OECD - Europe': 'Other',
    # 'OECD - Total': 'Other',
}

cpi['Country'] = cpi['Country'].apply(lambda c: country_replacements[c] if c in country_replacements else c)
cpi['Region'] = cpi['Country'].apply(lambda c: country_region_map.get(c, None))

date_start = datetime.datetime(2012, 10, 1)
date_end = datetime.datetime(2022, 10, 1)

plot_df = cpi.loc[(cpi.TIME > date_start) & (cpi.TIME <= date_end), ['Country', 'Region', 'Value', 'TIME']]

color_lower = -0.02
color_upper = 0.1

plot_df['Color'] = plot_df['Value'].clip(lower=color_lower, upper=color_upper)

charts = []

for r in region_order:
    chart_df = plot_df[plot_df['Region'] == r]
    
    chart = alt.Chart(chart_df).mark_rect(opacity=0.9).encode(
        x=alt.X('yearmonth(TIME):T', axis=alt.Axis(format="%Y" if r == region_order[-1] else " ", tickCount='year' if r == region_order[-1] else 0), title=''),
        y=alt.Y('Country:O', title=r),
        color=alt.Color('Color:Q', title='Inflation', scale=alt.Scale(scheme='redyellowgreen', reverse=True, domain=[color_lower, color_upper]), legend=alt.Legend(format=".0%")),
        tooltip=['Country',
                 alt.Tooltip('TIME', title='Date', format='%b %Y'),
                 alt.Tooltip('Value', title='Inflation (YoY)', format=".1%")]
    ).properties(
        height=len(set(chart_df['Country'])) * 15,
        width=550
    )
    
    charts.append(chart)
    
alt.vconcat(*charts).configure_concat(
    spacing=10
)

Source: OECD (2022), Inflation (National CPI, % change vs. prior year, seasonally adjusted). doi: 10.1787/eee82e6e-en

Both European and other developed market countries have seen relatively stable inflation numbers throughout the 2010s with a material uptick starting in 2021 (well before February 2022). Emerging market countries have seen a much greater and much more idiosyncratic development of inflation rates.