Modeling Topic Trends in FOMC Meetings
By: Giri Rabindranath
Tags: Topic Modeling, Text Analytics, Naturallanguageprocessing, Fed Fomc, Data Science

Contents

The Federal Open Market Committee (FOMC) sets monetary policy in the US. It has 12 members who meet 8 times per year to discuss interest rates and other economic matters. Investors pay close attention to the outcomes from these meetings — they can have significant consequences for US and global financial markets.

The minutes of FOMC meetings are released three weeks after each meeting. Through the minutes, investors can get a better understanding of the content of FOMC meetings. This helps with interpreting FOMC decisions and understanding the possible consequences for financial markets.

In this article I show how topic modeling, an area of natural language processing (NLP), can help to analyze the content of FOMC meetings. I use Latent Dirichlet Allocation (LDA), a popular topic modeling approach, to identify the key themes, or topics, discussed in the meeting minutes.

Topic modeling and LDA

Topic modeling is a form of unsupervised learning that can be applied to unstructured text data. It identifies groups of words or phrases that have similar meaning — topics — using statistical techniques.

LDA works by assuming that each document has a mix of underlying (latent) topics, and that each topic is made up of words from a specified dictionary. By observing the words within a set of documents, LDA infers the topics that fit with those words based on a probabilistic framework.

The mix of topics in a chronological series of text documents, such as FOMC minutes, changes over time. With LDA, you can observe this changing mix. The changing mix of FOMC topics is of interest to investors and market observers as it indicates areas of relative focus in FOMC discussions.

To learn more about topic modeling and LDA, including a hands-on example, see this introductory article.

Analysis approach

I analyze trends in the FOMC minutes using the following approach:

Collect the FOMC minutes to be analyzed

Prepare the minutes for analysis

Run an LDA model on the minutes

Extract the changing mix of topics over time

The LDA model requires:

The set of minutes transcripts being analyzed — the corpus — which we’ll use for training the model and for topic analysis

The dictionary of words to form the model vocabulary — this can be derived from the corpus

I implement LDA using the gensim package in Python. This is a powerful yet accessible package for topic modeling.

My analysis draws upon the work of academic and industry research into FOMC topic modeling (Jegadeesh and Wu [1] and Saret and Mitra [2]). Researchers and practitioners are increasingly using NLP approaches to gain better insights into financial market dynamics. This article presents one such approach.

Implementation

In the following, I step through and explain the key sections of code to implement the analysis in Python (v3.7.7).

For a full listing of the code, please see the expanded version of this article.

Import libraries

We’ll need libraries for requesting and parsing minutes transcripts from the FOMC website (requests and BeautifulSoup), text pre-processing (regular expressions and SpaCy), analyzing and displaying results (pandas, numpy, wordcloud and matplotlib) and LDA modeling (gensim).

import requests

import re

from bs4 import BeautifulSoup

import pandas as pd

import numpy as np

import gensim

import gensim.corpora as corpora

from gensim import models

import matplotlib.pyplot as plt

import spacy

from pprint import pprint

from wordcloud import WordCloud nlp = spacy.load("en_core_web_lg")

nlp.max_length = 1500000 # Ensure sufficient memory

Sourcing FOMC minutes

You can source FOMC minutes transcripts directly from the FOMC website.

Minutes transcripts on the FOMC website. Screenshot by Author.

For this analysis, I sourced minutes of FOMC meetings from October 2007 to July 2020 (the period for which current HTML formatting applies). This provides a good sample — from the aftermath of the 2007 financial crisis to the period following the 2020 COVID-19 pandemic.

I set up variables for the first part of the URL path ( URLPath ) and the URL extension ( URLExt ), as these are common elements of the URL path for all the minutes transcripts. I then create a list of dates for the minutes being analyzed ( MinutesList ).

Setting up URL paths for sourcing FOMC minutes transcripts

Setting up the corpus

The corpus is the collection of FOMC meeting transcripts that we’re analyzing. It’s also used for training our LDA model.

There are a number of steps in setting up the corpus:

Text pre-processing — we clean the transcripts by removing special characters, extra spaces, stop words and punctuation, then lemmatizing and selecting the parts-of-speech that we wish to retain (nouns, adjectives and verbs) (see this explanatory article to learn more about text pre-processing in natural language workflows)

Extract paragraphs from each of the transcripts — analysis by paragraph lends to better LDA analysis, but we ignore small paragraphs as they don’t add much value (I use a variable called minparalength to set the minimum length of paragraph extracted)

to set the minimum length of paragraph extracted) Set up lists — containing (i) the paragraphs from all the FOMC minutes ( FOMCMinutes ) as a ‘list of lists’, where each sub-list is a paragraph — this is a format suitable for input into the LDA model, (ii) a single list of all the paragraphs ( FOMCWordCloud ), ie. not a ‘list of lists’, which is used for generating a word cloud of the corpus, and (iii) a list containing the date and ‘weight’ of each paragraph in the corpus ( FOMCTopix ) — this is needed to aggregate the topic mixes of each paragraph into a combined topic mix for each meeting (see later).

To calculate the weight of each paragraph, I first calculate the total number of characters in each minutes transcript and store this in a variable called cum_paras . Then, for each paragraph I calculate the paragraph’s length (number of characters len(para) ) and divide it by cum_paras to arrive at the weight for that paragraph in the minutes transcript. I store the result in FOMCTopix .

Note that the total weights of all paragraphs in a given minutes transcript will sum to 1.

To set up the corpus, I define a function called PrepareCorpus which steps through each of the minutes transcripts, sources it and applies the above steps.

Preparing the FOMC minutes corpus

We can now call the above function to prepare our corpus.

# Prepare corpus

FOMCMinutes, FOMCWordCloud, FOMCTopix = PrepareCorpus(urlpath=URLPath, urlext=URLExt, minslist=MinutesList, minparalength=200)

I set minparalength to 200 — this seems to be a good length for capturing paragraphs which have meaningful content. Shorter paragraphs tend to contain greetings or administrative comments.

Inspecting the corpus

We can see what the prepared corpus looks like by generating a word cloud.

# Generate and plot WordCloud for full corpus

wordcloud = WordCloud(background_color="white").generate(','.join(FOMCWordCloud)) # NB. 'join' method used to convert the list to text format plt.imshow(wordcloud, interpolation='bilinear')

plt.axis("off")

plt.show()

Word cloud of FOMC minutes corpus. Image by Author.

We see a number of words in the corpus that are typical of FOMC meetings, including “federal”, “fund rate”, “market” and “monetary policy”.

Training the LDA model

To train our LDA model, we first need to form a dictionary from our corpus. We map the corpus to word IDs, then convert the words using a bag-of-words approach and finally apply TF-IDF to the result. This process is called text representation.

# Form dictionary by mapping word IDs to words

ID2word = corpora.Dictionary(FOMCMinutes) # Set up Bag of Words and TFIDF

corpus = [ID2word.doc2bow(doc) for doc in FOMCMinutes] # Apply Bag of Words to all documents in corpus

TFIDF = models.TfidfModel(corpus) # Fit TF-IDF model

trans_TFIDF = TFIDF[corpus] # Apply TF-IDF model

We use TF-IDF as it produces better results than using bag-of-words alone. TF-IDF adjusts for words that appear frequently but have low semantic value, relative to words that appear infrequently but with higher semantic value. This favors words which have more meaning in the context of the corpus.

For more information about bag-of-words, TF-IDF and other text representations, see this explanatory article.

We next select the model parameters that we wish to use and run the model.

SEED = 130 # Set random seed

NUM_topics = 8 # Set number of topics

ALPHA = 0.15 # Set alpha

ETA = 1.25 # Set eta # Train LDA model using the corpus

lda_model = gensim.models.LdaMulticore(corpus=trans_TFIDF, num_topics=NUM_topics, id2word=ID2word, random_state=SEED, alpha=ALPHA, eta=ETA, passes=100)

The parameters shown above are key inputs for an LDA model. NUM_topics , in particular, needs to be set by the user. The other parameters ( SEED , ALPHA and ETA ) help to produce better results with fine-tuning.

To learn more about LDA parameters and the process for fine-tuning them, please see the sections on ‘Model evaluation’ and ‘Model improvement’ in this introductory article.

How do we evaluate the results of our LDA model?

There are quantitative approaches for doing this, but when applied to a text corpus it’s helpful to produce results that have a sensible human interpretation. This requires judgement.

In terms of quantitative measures, a common measure for evaluating LDA models is the coherence score. This measures the semantic similarity (likeness of meaning) between the words in each topic of an LDA model. All else equal, a higher coherence score is better.

We can measure the coherence of our model using the CoherenceModel in gensim.

# Set up coherence model

coherence_model_lda = gensim.models.CoherenceModel(model=lda_model, texts=FOMCMinutes, dictionary=ID2word, coherence='c_v') # Calculate coherence

coherence_lda = coherence_model_lda.get_coherence()

The coherence score for our model is:

Coherence Score: 0.63779581

This is a fairly good result, based on careful selection of the above parameters.

How did we arrive at our parameters?

In choosing the number of topics ( NUM_topics ), I was guided by Jegadeesh and Wu [1], who choose 8 topics for their LDA model — I chose the same, as it tended to produce sensible topic interpretations.

To select the other parameters, you can explore the effect of changing parameter values on model coherence. The following code does this for the ALPHA parameter — you can use this as a template to fine-tune any of the other parameters.

Exploring the impact of changing parameter values (in this case, alpha) on LDA model coherence

The output of the above code is:

LDA model coherence by varying Alpha. Image by Author.

The above plot suggests that an alpha of 0.15 produces a high coherence — this is the value of alpha adopted.

Note that by setting the SEED parameter, we ensure that the model will produce the same results with repeated runs.

Analyzing the topic mix

Since we’re using the same corpus for training and analysis, we don’t need to run the trained LDA model on a new set of documents. Instead, we can go straight to analyzing the corpus.

Our goal is to calculate the topic mix for each of the minutes transcripts in the corpus. By plotting the topic mix over the chronological sequence of the meetings (since each meeting occurred on a given date), we can observe any trends or changes in the topic mix over time.

Recall that we divided our corpus into individual paragraphs, hence our model will produce a topic mix for each paragraph of each transcript in the corpus. The topic mix is a proportionate allocation to each of the ( NUM_topics ) topics in the model for each paragraph. The proportions across all topics in the paragraph will sum to 1.

We now need to convert these paragraph-level topic mixes to document-level topic mixes (ie. to create an aggregate topic mix for each meeting).

Once again I was guided by Jegadeesh and Wu [1]. They calculate document-level topic mixes (each document being a minutes transcript in our case) using a weighted sum of paragraph-level topic mixes — I adopt the same approach.

We’ve already calculated each paragraph’s weight when we set up our corpus and stored it in FOMCTopix . Let’s call these weights the ‘document-weight’ of each paragraph. Using this, we generate aggregate topic mixes as follows:

Extract the topic mix for each paragraph and store the result in FOMCTopix alongside the paragraph’s meeting date and its document-weight

alongside the paragraph’s meeting date and its document-weight Multiply each topic proportion in the paragraph’s topic mix by the paragraph’s document-weight

For each document (ie. individual meeting transcript), sum the topic proportions, topic by topic, across all topics for all paragraphs in the transcript

We will end up with the weighted topic mixes for each minutes transcript, where the weights are based on the relative lengths of the paragraphs within each transcript.

I extract each paragraph’s topic mix using the get_document_topics method of gensim and append the results to FOMCTopix , which is in a list format. I then convert this list to a data frame object and call the pivot_table method to sum the topic proportions across all paragraphs within each minutes transcript.

Generating weighted topic proportions for all paragraphs

Note that I have assigned names to some of the topics in the above code — I’ll discuss this in the next section.

Interpreting topics

Although LDA topic modeling is a quantitative process, the identified topics may not always lend themselves to easy interpretation. You can apply judgment in how you label and select topics depending on your analysis.

The considerations and challenges of topic model evaluation are discussed further in this article.

You can explore topic contents at-a-glance by generating word clouds.

topic = 0 # Initialize counter

while topic < NUM_topics:

# Get topics and frequencies and store in a dictionary structure

topic_words_freq = dict(lda_model.show_topic(topic, topn=50))

topic += 1



# Generate Word Cloud for topic using frequencies

wordcloud = WordCloud(background_color="white").generate_from_frequencies(topic_words_freq)

plt.imshow(wordcloud, interpolation='bilinear')

plt.axis("off")

plt.show()

In our case, I had set 8 topics in the modeling ( NUM_topics = 8) based on guidance from Jegadeesh and Wu [1]. This resulted in topics that had a high coherence and good interpretability. Not all of the 8 topics were entirely useful however — some of them were a bit ‘noisy’ and didn’t add much to the analysis. I therefore chose 4 topics on which to focus.

Saret and Mitra [2] also used 8 topics in their modeling but reconfigured this into a smaller number of topics (6 in their analysis), based on what they considered to be sensible interpretations.

For the 4 topics which I chose, I assigned labels based on the words in the topics and also in comparison with labels used by Jegadeesh and Wu [1]. The topics and labels that I chose are:

Inflation

Consumption

Market

Policy

The word clouds for these topics are shown below.

Word cloud of INFLATION topic. Image by Author.

Word cloud of CONSUMPTION topic. Image by Author.

Word cloud of MARKET topic. Image by Author.

Word cloud of POLICY topic. Image by Author.

Topic mix results

We’re now ready to plot the topic mix of our chosen topics over time.

# Plot results - select which topics to print

TopixAggDF.plot(y=['Inflation', 'Consumption', 'Market', 'Policy'], kind='line', use_index=True)

Let’s see what this looks like:

Topic mix over time of FOMC minutes. Image by Author.

The shaded region (2008–09) represents a US recession period (NBER-designated). The x-axis shows the date of FOMC meetings and the y-axis shows the proportion of each meeting that each topic makes up, based on our analysis.

Interpreting the results

We observe the following from our plot of the FOMC topic mix over time:

There is a noticeable variation in the topic mix over time, particularly for the policy and consumption topics

There was a significant increase in the time allocated to discussing policy in the period following the 2008–09 recession, and this coincided with a significant reduction in the time spent discussing consumption

Time spent discussing inflation and the market has been more stable, albeit with a higher proportion during the recession and some divergence during 2014–2018 (ie. more time on inflation and less time on the market)

These observations appear to make sense in light of historical circumstances.

Policy discussions in particular have been an important area for the FOMC since the 2008–09 recession. This reflects the role that monetary policy has had on US financial markets since then, and the significant policy decisions that the FOMC has made (eg. changing the federal funds target rate from over 5% in 2007 to below 0.25% by 2009).

The increase in time spent discussing inflation since 2014 (until recently) reflects the degree of concern the FOMC has had around the management of inflation (which has been persistently low).

Similarly, it’s not surprising that more time than usual has been spent discussing financial markets during the recession and also more recently (starting from a low level prior to 2007). There were important market operations that were initiated or amended during these times.

While subject to some judgment and interpretation, the LDA model has provided a useful quantitative synopsis of the FOMC topic mix over time. This illustrates the potential for NLP techniques to assist the money management process.

In the words of Saret and Mitra [2] (pp. 3–4, with slight modification):

“Market observers trying to glean insights from [FOMC] meeting minutes once needed to rely on the subjective interpretation of so-called expert “Fed watchers” or their own interpretation. Now, asset allocators can apply natural language processing techniques to extract insights from the FOMC’s published meeting minutes, turning qualitative inputs into more easily analyzed, quantitative data.”

Conclusion

Topic modeling is a versatile and evolving area of natural language processing. In this article, we’ve seen how topic modeling can be used to observe the changing mix of topics in a text corpus over time.

Such use cases have the potential for a range of real-world applications. In relation to money management, topic modeling is already being added to the toolkit for making sense of financial markets (as evidenced by Saret and Mitra [2]).

This article was originally published in the High Demand Skills blog

References

[1] N. Jegadeesh and D. Wu, Deciphering Fedspeak: The Information Content of FOMC Meetings (2015), SSRN

[2] J. N. Saret and S. Mitra, An AI Approach to Fed Watching (2016), Two Sigma Street View