An Analysis of Muhammadu Buhari’s Tweet
By: Kafaru Simmie
Tags: Text Analytics, Sentiment Analysis, R Programming, Twitter, Data Science

Analyzing patterns using Text mining techniques

Muhammadu Buhari has been the President of Nigeria since 2015. There has been a lot of controversy around the president of the largest African nation, Nigeria. Especially since there have been a lot of boggling issues since the president's ascent to being the president of the nation. Particularly on Twitter, you’ll find a lot of tweeps spamming the President's tweets with comments such as IFB or or “I follow back” which is a way of protesting the president's rule as the GCFR. With over 3 million Twitter users, one would be curious to know the contents of the president's tweets attracting such comments by tweeps.

Background of Analysis

I decided to apply Text Analytics to understand key contents of the President's tweets, Sentiment Analysis to understand emotions and as well, some graph analysis to see the phrase(s) peculiar to the President's tweets.

You can read about the difference between Text Analytics and Sentiment Analysis here.

Data Collection

On Buhari’s Twitter page, you find that he has made about 4952 tweets over the last six years (2014–2020). You can find the dataset here.

The Data collection and analysis were all done in R using the rtweet package, which allows you to collect data from Twitter using Twitter’s developer API. However, there is a limitation on the free API to collecting tweets from user accounts, as you can only collect approximately 3200 from a single users’ timeline. I was able to collect 3224 tweets spanning between “2016–09–12 10:10:32" & “2020–11–13 15:32:25” using the code below;

library(rtweet)

library(tidyverse) #Get as many tweets as possible

df <- get_timeline("MBuhari", n = 3200) #Write to csv

df %>%

write_as_csv("buhari.csv")

The result of the query got about 3224 rows, 90 columns.

Data Exploration

Let’s find out the trend of the presidents tweeting pattern over the years;

#Lets take a look at his tweet trend over the years

df %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

mutate(yearmon = format(as.Date(date), "%Y-%m")) %>%

mutate(yearmon = as.yearmon(yearmon)) %>%

group_by(yearmon) %>%

count() %>%

ggplot(., aes(yearmon, n, group = 1)) +

geom_line(size = 1, color = "#00ba38") +

geom_point(color = "#f8766d") +

geom_smooth(method = "lm", se = F) +

annotate(geom = "label", vjust = -0.1,

label="Humanitarian \ Crisis",x = as.yearmon("Dec 2016"),

y= 154, color = "black", size =3) +

annotate(geom = "label", vjust = -0.1,

label="Covid'19",x = as.yearmon("Apr 2020"),

y= 189, color = "black", size =3) +

annotate(geom = "label", vjust = -0.1,

label="Corruption",x = as.yearmon("Sep 2018"),

y= 163, color = "black", size =3) +

annotate(geom = "label", vjust = -0.1,

label="Football/Corruption/Tragedy",x = as.yearmon("Oct 2019"),

y= 157, color = "black", size =3) +

annotate(geom = "label", vjust = -0.1,

label="Polio",x = as.yearmon("Jun 2020"),

y= 154, color = "black", size =3) +

theme_minimal() +

theme(axis.text.x = element_text(angle = 20)) +

scale_x_yearmon(format = "%b %Y", n = 10) +

labs(title = "Buhari's Tweet Trend",

subtitle = "Sept2016 - Nov2020")

This peak period will most likely correlate to a time of either uprising or celebration in the country. Some of the major reasons for the multiple peaks in 2020 would be the COVID-19 outbreak, EndSARS protest, and other pressing issues in the nation.

We go further to perform text analysis of the tweets and see the top words used in his tweets.

df %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(text = tolower(text)) %>%

mutate(text = gsub("brt", "", text)) %>%

mutate(text = gsub("t.co", "", text)) %>%

mutate(text = gsub("https", "", text)) %>%

mutate(text = gsub("amp", "", text)) %>%

mutate(text = gsub("Ã¢", "", text)) %>%

unnest_tokens(word, text) %>%

anti_join(stop_words) %>%

count(word, sort = T) %>%

arrange(desc(n)) %>%

top_n(20) %>%

ggplot(., aes(reorder(word, n), n)) +

geom_bar(stat = "identity") +

coord_flip() +

labs(title = "Top 20 most used words", x = "Words")

We do a further classification, to see which words were dominant across each year contained in the tweets.

#Most used words for each year

df %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

mutate(text = tolower(text)) %>%

mutate(text = gsub("brt", "", text)) %>%

mutate(text = gsub("t.co", "", text)) %>%

mutate(text = gsub("https", "", text)) %>%

mutate(text = gsub("amp", "", text)) %>%

mutate(text = gsub("â", "", text)) %>%

unnest_tokens(word, text) %>%

anti_join(stop_words) %>%

group_by(year) %>%

count(word, sort = T) %>%

arrange(desc(n)) %>%

mutate(word = reorder(word, n)) %>%

slice(1:10) %>%

ungroup() %>%

ggplot(., aes(reorder_within (word, n, year), n, fill = as.character(year))) +

geom_col(show.legend = F) +

coord_flip() +

facet_wrap(~year, ncol = 2, scales = "free") +

xlab("Words") +

ggtitle("Top 10 Words", subtitle = "2016-2020") +

theme_dark() +

theme(plot.title = element_text(hjust = 0.5, face = "bold"),

plot.subtitle = element_text(hjust = 0.5))

A bigram Analysis can also reveal the common phrases used by the handle. There appears to be a consistent pattern in the word usage across the different years, perhaps the same handler (if there is one).

#Bigram Analysis

df %>%

as.data.frame() %>%

mutate(text = unlist(text)) %>%

mutate(text = gsub("brt", "", text)) %>%

mutate(text = gsub("t.co", "", text)) %>%

mutate(text = gsub("https", "", text)) %>%

tidytext::unnest_tokens(bigram, text, token = "ngrams", n = 2, collapse = F) %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

group_by(year) %>%

count(bigram, sort = TRUE) %>%

ungroup() %>%

separate(bigram, c("word1", "word2"), sep = " ") %>%

filter(!word1 %in% stop_words$word) %>%

filter(!word2 %in% stop_words$word) %>%

group_by(year) %>%

count(word1, word2, sort = TRUE) %>%

drop_na() %>%

ungroup() %>%

unite(bigram, word1, word2, sep = " ") %>%

group_by(year) %>%

slice(1:10) %>%

ungroup() %>%

mutate(bigram = reorder_within(bigram, n, year)) %>%

ggplot(., aes(bigram, n, fill =as.character(year))) +

geom_col(show.legend = F) +

facet_wrap(~year, ncol = 2, scales = "free") +

coord_flip() +

xlab("Bigrams") +

ggtitle("Top 10 Bigrams", subtitle = "2016-2020") +

theme_dark() +

theme(plot.title = element_text(hjust = 0.5, face = "bold"),

plot.subtitle = element_text(hjust = 0.5))

An hourly count of the tweets faceted for each year reveals an interesting fact. You should expect the president will be tweeting at later hours of the day. Typically between 3 pm and 7 pm.

#Hourly tweet Trend

df %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(time = hms(time)) %>%

mutate(hour = lubridate::hour(time)) %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

group_by(hour, year) %>%

count() %>%

ggplot(., aes(factor(hour), n, fill = as.character(year))) +

geom_col(show.legend = F) +

facet_wrap(~year, ncol = 2, scales = "free") +

ggtitle("Tweets Count by Hour of Day") +

xlab("Hour")

Sentiment Analysis

Sentiment Analysis can help us detect the kinds of emotions conveyed by each tweet, and each word used either positively or negatively.

Firstly, I will attempt to examine the top words either used positively or negatively.

#Sentiments

df %>%

mutate(text = gsub("brt", "", text)) %>%

mutate(text = gsub("t.co", "", text)) %>%

mutate(text = gsub("https", "", text)) %>%

unnest_tokens(word, text) %>%

anti_join(stop_words) %>%

inner_join(get_sentiments("bing")) %>%

count(word, sentiment, sort = TRUE) %>%

group_by(sentiment) %>%

top_n(10) %>%

ggplot(., aes(reorder(word, n), n, fill = sentiment)) +

geom_col(show.legend = F) +

facet_wrap(~sentiment, ncol = 2, scales = "free") +

coord_flip() +

labs(x = "Words")

A more interesting approach would be to see the pattern of positivity (or negativity) over time. I will make it overall (2016–2020) and as well for each year.

#Yearly trend of sentiments

dataInput <- df

data_format <- dataInput %>%

mutate(text = iconv(text, from = "latin1", to = "ASCII")) %>%

mutate(text = tolower(text)) %>%

mutate(row_id = row_number()) %>%

mutate(text = tolower(text)) %>%

mutate(text = gsub("brt", "", text)) %>%

unnest_tokens(word, text) %>%

anti_join(stop_words) %>%

inner_join(get_sentiments("bing")) %>%

count(sentiment, row_id, screen_name) %>%

spread(sentiment, n, fill = 0) %>% # made data wide rather than narrow

mutate(sentiment = positive - negative) All_banks <- dataInput %>%

mutate(row_id = row_number()) data_format <- data_format %>%

left_join(All_banks, by = "row_id") #convert negative column to negative values

data_format2<- data_format %>%

mutate(negative = negative * (-1)) data_format2 %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

mutate(yearmon = format(as.Date(date), "%Y-%m")) %>%

mutate(yearmon = as.yearmon(yearmon)) %>%

group_by(yearmon) %>%

summarise(negative = sum(negative), positive = sum(positive)) %>%

gather(key = "sentiment", value = "n", 2:3) %>%

ggplot(., aes(yearmon, n, group = sentiment, color = sentiment)) +

geom_line(size = 0.8) +

labs(title = "Sentiment Trend", x = "YearMonth", subtitle = "2016-2020") +

theme_minimal() +

scale_x_yearmon(format = "%b %Y", n = 10) +

theme(axis.text.x = element_text(angle = 30))

Finally, we can include a bigram graph to show connections between words.

#Bigram analysis

a <- df %>%

as.data.frame() %>%

mutate(text = unlist(text)) %>%

mutate(text = gsub("brt", "", text)) %>%

mutate(text = gsub("t.co", "", text)) %>%

mutate(text = gsub("https", "", text)) %>%

tidytext::unnest_tokens(bigram, text, token = "ngrams", n = 2, collapse = F) %>%

separate(created_at, into = c("date", "time"), sep = " ") %>%

mutate(date = ymd(date)) %>%

mutate(year = year(date)) %>%

group_by(year) %>%

count(bigram, sort = TRUE) %>%

ungroup() %>%

separate(bigram, c("word1", "word2"), sep = " ") %>%

filter(!word1 %in% stop_words$word) %>%

filter(!word2 %in% stop_words$word) %>%

group_by(year) %>%

count(word1, word2, sort = TRUE) %>%

ungroup() %>%

drop_na() %>%

arrange(desc(n)) %>%

unite(bigram, word1, word2, sep = " ") %>%

group_by(bigram) %>%

count(sort = T) %>%

ungroup() %>%

top_n(40) %>%

graph_from_data_frame() %>%

ggraph(., layout = "fr") +

geom_edge_link() +

geom_node_point(color = "lightblue", size = 3) +

geom_node_text(aes(label = name), vjust = 0.6, hjust = 0.2) +

theme_void() a

Conclusion

While I won’t make so much of inferences or conclusions from these tweets (I’ll leave that to researchers… lol), there are certain obvious things. It includes that the handler of this account has been consistent with the use of certain words, and it doesn’t appear that the president makes those tweets by himself (if you examine the third person word usage).