Sentiment Analysis of COVID-19 Vaccine Tweets | by Sejal Dua | Towards Data Science

It’s been a long year of sickness, devastation, grief, and hopelessness, but the global rollout of COVID-19 vaccines has sparked feelings of relief and newfound optimism for so many. The discussion of vaccination progress, accessibility, efficacy, and side effects is ongoing, and it is permeating through news stories and Twitter spheres each and every day. However, as online users, our visibility is limited to our own echo chambers. Thus, the motivation for this project is to widen my perspective on the state of the global pandemic by harnessing the power of Twitter data.
It would be nearly impossible for a human to read through and digest everything that people have been tweeting about with regards to COVID-19 vaccines. Fortunately, with the help of natural language processing (NLP) techniques, we can peer into an enormously complex and far-ranging discussion by way of textual featurization, sentiment analysis, and word cloud visualizations.
The following work employs a Kaggle dataset called “All COVID-19 Vaccines Tweets”. The data was collected using a Python package called Tweepy, which enables a user to access the Twitter API if they have successfully created a Twitter Developer account and obtained access credentials. In this case, since the data was all pre-collected and stored in a 10 MB tabular format on Kaggle, it is accessible to anyone who wishes to get their hands on it. The data includes tweets pertaining to a variety of vaccines, including Pfizer/BioNTech, Sinopharm, Sinovac, Moderna, Oxford/AstraZeneca, Covaxin, and Sputnik V. For each vaccine, a relevant search term was used to query for recent tweets.
The primary goal of the exploratory data analysis phase of this project was to get acquainted with the columns of the data frame and start brainstorming research questions.
Starting with the step of loading the data using pandas, some basic data frame operations allow us to see that, for each tweet, all of the following information is available:
information about the user who tweeteduser_name: Twitter handleuser_location: where in the world the person tweets from (NOTE: there is no validation here... “your bed” is technically acceptable)user_description: user-written biographyuser_created: when they created their Twitter accountuser_followers: number of followersuser_friends: number of accounts the user is followinguser_favourites: number of tweets the user has likeduser_verified: indicates if the user is a well-known figure (boolean)
information about the tweet itselfid: indexing value for Twitter APIdate: a datetime object in the form of YYYY-MM-DD HH:MM:SStext: the tweet itself (**MOST IMPORTANT**)hashtags: list of hashtags used in the tweet (without ‘#’ character)source: which device was used for the tweetretweets: number of retweets received at the time the data was collectedfavorites: number of likes received at the time the data was collectedis_retweet: indicates if the tweet is original or a retweet (boolean)
Out of the above columns, text, date, user_name, user_location, hashtags, favorites, and retweets will be most relevant for this analysis. Though the tweets were queried using vaccine-related keywords, the specific vaccine being referred to in the tweet is not explicitly included as a column in the dataset. Therefore, we will need to filter for vaccine references in order to do any comparative analysis.
A great first step when doing any EDA is making some charts of our columns (or features) and their distributions. The pandas built-in function df.describe() can help us see at-a-glance statistics of each numerical column.
We can see from the above figure that in this dataset of vaccine tweets, the average user has more than one thousand friends and has liked thousands of other tweets, so these are primarily active Twitter users whose tweets we are analyzing. We can also see that the average retweet count is 4 and the average like count per tweet is 18. However, we should take these statistics with a grain of salt because the ‘std’ (standard deviation) row shows us that there is a lot of variation in the dataset, as one might imagine.
There are a total of 16,170 tweets in this dataset (at the time of completing the project), so in order to feasibly inspect some of the tweets for intuition before we begin, we can take a look at the most retweeted tweets. A high retweet count indicates that the tweet was likely informative enough to be shared widely or was relatable enough to “go viral,” in Twitter speak. We can preview the top 10 most retweeted tweets by executing the following operation on our data frame:
df.sort_values(by='retweets', ascending=False)[['text', 'date', 'user_name', 'user_location', 'hashtags', 'favorites', 'retweets']].head(n=10)
From the above image, we can see that many of the most retweeted tweets were tweeted from users in India in March and were referencing the Covaxin vaccine, specifically. It is also apparent that three of the top 10 most retweeted tweets come from an account called “Megh Updates 🚨” and seem to be news updates rather than opinion-based comments about vaccines. This makes sense because informational tweets are generally more likely to be retweeted than opinion-based tweets. Interestingly, the top most retweeted tweet comes from a user named Dr. J Jaishankar, an Indian diplomat and politician who is the current Minister of External Affairs of the Government of India. His tweet is just a status update saying “got my jab. for the curious, it was covaxin. felt secure, will travel safely.” Though this message does not seem informative or opinionated, since Dr. Jaishankar is such a well-known figure in India and in the global political space, it makes sense that his large Twitter following likely reacted positively toward his status update.
Now, we can do another quick inspection to get a sense of how the discussion started to pick up momentum on Twitter in the early stages of the vaccine rollout:
df.sort_values(by=['date', 'favorites'], ascending=[True, False])[['text', 'date', 'user_name', 'user_location', 'hashtags', 'favorites', 'retweets']].head(n=10)
The above preview sorts the dataset by date (ascending order), and then by which tweets received the highest like / favorite count (decending order). We can see that the COVID-19 vaccine discussion starts to emerge on Twitter the day after the approval of the Pfizer-BioNTech vaccine, December 12, 2020. Most tweets reference the PfizerBioNTech vaccine, but these tweets clearly did not reach a large audience, with the most liked tweet that day having only 37 likes and 2 retweets.
Pivoting to the sentiment analysis portion of this work, we can take this intuition of some of the tweets being informative and some of the tweets being opinionated to partition the greater discourse into separate sets of tweets with similar quantitative features. These features can be obtained using a Python package called TextBlob, which provides an API for NLP tasks such as part-of-speech tagging, noun phrase extraction, sentiment analysis, classification, translation, and more.
To install TextBlob, make sure to execute the following two commands in a Terminal window:
$ pip install -U textblob$ python -m textblob.download_corpora
TextBlob’s sentiment analysis processing employs two key metrics: polarity and subjectivity. The polarity score is a float within the range [-1.0, 1.0], and it reflects the emotional charge of a statement or passage. Subjectivity is a float within the range [0.0, 1.0], where 0.0 is very objective and 1.0 is very subjective. Let’s check out a few simple examples:
>>> TextBlob("So excited to get my vaccine!").sentimentSentiment(polarity=0.46875, subjectivity=0.75)>>> TextBlob("Is the vaccine painful?").sentimentSentiment(polarity=-0.7, subjectivity=0.9)>>> TextBlob("The Pfizer vaccine is now FDA approved").sentimentSentiment(polarity=0.0, subjectivity=0.0)
In the first example, we can observe that TextBlob recognizes a relatively positive emotional charge associated with the statement, whereas it recognizes a negative emotional charge associated with the second example. In both the first and second examples, it correctly identifies that someone expressing how they feel towards getting vaccinated is highly subjective. In the third example, the statement is identified as neutral in polarity and highly objective. These three examples showcase how TextBlob sentiment analysis may help us derive quantitative textual features.
While TextBlob is trained on a large corpora and employs a fairly reliable language model, its service is best suited to recognize syntactical and semantic features from textual data rather than to understand the text. TextBlob is not context-aware, so the scores returned from its API should be interpreted loosely, in a way that prompts further analysis.
As an example of a shortcoming of TextBlob:
>>> TextBlob("I tested positive for COVID-19").sentimentSentiment(polarity=0.227272727, subjectivity=0.54545454)
TextBlob gets confused by the word “positive” because it is not trained to recognize medical jargon. It classifies this sentence as positively charged and fairly subjective even though it actually should be negative or neutral and objective. This is important to be aware of when we interpret its classifications of each tweet in our dataset. For tasks that require more context-aware language models, I recommend checking out nltk, vader, sklearn, and allennlp.
Let’s take a look at how TextBlob perceives the sentiment of the following tweet by Texas governor Greg Abbott.
for sentence in blob.sentences:    print(sentence)    print("polarity:", sentence.sentiment.polarity)    print("subjectivity:", sentence.sentiment.subjectivity)
Iterating through each sentence and retrieving polarity and subjectivity scores, we obtain the following results:
Today Texas surpassed 8 million vaccinations.polarity: 0.0subjectivity: 0.0It was just 4 days ago that we passed 7 million.polarity: 0.0subjectivity: 0.0The positivity rate dropped even lower--to 6.08%--the lowest since May 31st.polarity: 0.0subjectivity: 0.0Hospitalizations went down again also.polarity: -0.15555555555555559subjectivity: 0.2888888888888889Great job Texans!polarity: 1.0subjectivity: 0.75Vaccines are always voluntary, never forced.polarity: 0.15000000000000002subjectivity: 0.2
The first three sentences have been identified as having neutral polarity and maximum objectivity, which makes sense given that they contain factual trends regarding the vaccine rollout and the state of the pandemic. Interestingly, the fourth sentence, “Hospitalizations went down again also,” is labeled as having a negatively charged sentiment with mild subjectivity. This is likely because the words “hospitalization” and “down” have negative connotations, and there are also no numbers or factual pieces of evidence here. If Governor Abbott had said “Hospitalizations were reduced by X %,” that would be considered a neutral and objective statement. “Great job Texans!”, on the other hand, is a prime example of a positive, highly subjective statement.
We can now apply the TextBlob API onto our Twitter data to perform sentiment analysis on all 16,170 tweets!
df['polarity'] = df['text'].apply(lambda x: TextBlob(x).sentiment.polarity)df['subjectivity'] = df['text'].apply(lambda x: TextBlob(x).sentiment.subjectivity)df.head()
The histograms above depict a breakdown of polarity and subjectivity scores for all tweets in the dataset. The majority of the tweets in the dataset seem to be informative vaccine updates, with neutral polarity and no subjectivity. Among the polar tweets, however, there are slightly more positively charged tweets than negatively charged tweets. We can infer that vaccine discourse on twitter is generally optimistic, but it would be nice to know what kinds of optimistic sentiments people are expressing and what feelings of anxiety or hopelessness people might be expressing.
We can inspect these types of tweets by sorting the data frame by polarity scores and then displaying the top 10 rows:
Some notable phrases from the above slice of negatively charged tweets include “ugh, I’m miserable”, “outrageous that...”, “worst headache of my life”, “what the f*ck”, “i feel like crap”, “greed at its worst”, and “terrible!”. Here, emojis have not been factored into the sentiment scores, but there are certainly ways to convert emojis to text if they are prominent enough to factor into the analysis. One evident shortcoming of TextBlob’s sentiment analysis is it does not recognize the word “blessed” as having a positive connotation. In row 8, when the user says, “so blessed to be fully vaccinated against this devastating virus,” the word “devastating” has likely confused the language model. The model fails to recognize that the vaccine serves as a defense against the devastating virus, which is a positive thing.
Similarly, when we inspect the top 10 most positively charged tweets, we notice a lot of highly subjective expressions. The most used words and phrases include “feel great”, “best”, “wonderful”, and “perfect”.
For the next component of this project, we will see if we can explore any trends with respect to time. First, it is valuable to visualize the temporal distribution of all of the tweets in the dataset.
In the graph above, it is evident that the apex of the discussion took place on March 1st. After investigating a bit deeper, I learned that Indian Prime Minister Narendra Modi received the first dose of Covaxin, an Indian-developed COVID-19 vaccine, on that day. This particular event was quite exciting and uplifting for Indians, as reflected by their activity on Twitter.
Among all of the tweets in the dataset, about half of them were designated by TextBlob as neutral in sentiment (polarity = 0.0), with the other half consisting of 75% positively charged tweets (polarity > 0.0) and 25% negatively charged tweets (polarity < 0.0).
The above plotly graphs provide a snapshot of how subjectivity scores and polarity scores varied, on average, over time. From the average polarity score graph above, we can hypothesize that the discourse on Twitter was optimistic prior to February, in anticipation for the distribution of the vaccine. In the months of February and March, the vaccine rollout escalated quite dramatically, and people started tweeting out status updates pertaining to their individual experiences. Time series analyses can be quite helpful if one has a research hypothesis pertaining to the effect of a specific event in time or if they are hoping to gain intuition surrounding an event. That said, our data pertains to multiple different vaccines, and the tweets are not divided by location, so it is quite difficult to infer what exactly a positive or negative sentiment entails. To study this further, we can use a visualization representation called word clouds.
The final step of this project is to generate color-coded word clouds to see which words are indicative of each sentiment. The recipe for doing this is roughly outlined below
Perform more thorough preprocessing such as spell checks, splitting spaceless phrases etc.
Calculate log likelihood values
Generate a synthetic corpus based on the log likelihood values
Generate smarter word clouds
The above word cloud depicts which words are typically used with respect to each sentiment for tweets mentioning either “Pfizer” and/or “BioNTech”. The positive tweets appear to be from people who have just received their first vaccine or are grateful for the job scientists and healthcare workers are doing, whereas the negative tweets seem to be from people who have suffered side effects, adverse reactions, or general discomfort after receiving the vaccine. The words used in neutral tweets pertaining to the Pfizer vaccine seem to resemble news headlines. Some of these words include “health”, “announced”, “FDA”, “approves”, “million”, “said”, and “vaccination”.
The word cloud for the Moderna vaccine yields similar insights as the one of Pfizer tweets. In the word cloud with negatively charged words, there are lots of references to side effects, arm soreness, chills, fever, headaches, feelings of tiredness, and other mild symptoms that people might feel inclined to share on Twitter. The neutral words include “supply”, “million”, “billion”, “clinic”, “mRNA”, “Canada”, “Philippines”, “increase”, “total”, and many others news-related terminology. Interestingly, there is a pretty frequent mention of IBM among neutral tweets, which likely relates to the announcement of Moderna and IBM Planning to Collaborate on COVID-19 Vaccine Supply Chain and Distribution Data Sharing. There are also positive and neutral references to Dolly Parton, who helped fund the Moderna vaccine and later received the Moderna vaccine. Similar to the positive Pfizer-specific tweets, positive Moderna-specific tweets tend to come from users expressing gratitude upon receiving the first dose of the vaccine.
Lastly, the word cloud for Covaxin includes lots of references to specific people and places in India. For the negatively associated tweets, the words “propaganda” and “political” seem intriguing enough to prompt further exploration. The positively associated tweets include a significant amount of references to prime minister Narendra Modi. Given that India is a nation with a strong sense of nationalistic pride, it makes sense that many of these tweets have positive sentiments. Also, from a cultural point of view, there are language nuances in this subset of the data versus the Pfizer and Moderna subsets. In India, if someone has just received the vaccine, they might say, “I got the jab,” which we otherwise may not have been aware of without these word cloud visualizations!
I do not believe there is ever a definitive end to a project, but rather, there is a point at which we decide to wrap things up. With this mindset, I like to conclude projects by brainstorming research questions that I would be interested in pursuing further:
Use the tweepy API to get tweets about the Johnson & Johnson Vaccine, and apply sentiment analysis onto them.
Which hashtags are people using? Is the use of hashtags correlated with higher like counts and/or retweet counts?
Analyze the faction of the tweets that include URLs. Do tweets with URLs have primarily neutral sentiments?
What are verified Twitter users saying about the COVID-19 vaccine?
What are people saying with respect to side effects? Which vaccine has the worst side effects?
Correlate the COVID-19 World Vaccination Progress dataset with this sentiment analysis to monitor how attitudes are changing towards the vaccine as the rollout continues.
If you made it this far, thank you so much for reading! The code for this work can be found in the following GitHub repository:
github.com
If you would like to check out more of my work or get in touch, feel free to visit my website, GitHub, LinkedIn, and/or Twitter. I would love to connect!