Toxicity Analysis of a Twitter Thread: Analyzing Replies to President Trump’s Tweet about Contracting the Novel Coronavirus
On October 2nd, 2020, U.S. President Donald Trump tweeted that he and the First Lady of the United States (FLOTUS), Melania Trump, both tested positive for COVID-19 (see Figure 1). Within seconds, his tweet received thousands of replies on Twitter. This post will detail our exploratory data analysis of these replies.
To collect and analyze our dataset, we used Communalytic, an online community analyzer for studying anti-social behaviour. Communalytic uses Twitter API’s version 2.0 to collect replies to a given tweet. Once tweets are collected, Communalytic uses Google’s Perspective API to perform a toxicity analysis, a process based on a machine learning algorithm that examines each post and assigns toxicity scores. After toxicity scores are calculated, we exported the processed dataset from Communalytic to conduct an exploratory data analysis using a custom script in Python as outlined below.
The main goal of this post is to demonstrate the type of analysis that can be performed using data collected from public Twitter threads with the help of Communalytic and Python libraries. This post will also show how to explore a potential relationship between the toxicity scores of individual posts and their availability status a few days after the original data collection.
For information about how to collect Twitter data with Communalytic, see our online tutorial here.
The dataset consists of 298,172 replies to Donald Trump’s tweet announcing his COVID-19 diagnosis, posted on October 2nd between 6:00am and 12:30pm (ET).
Each tweet in the dataset includes a number of metadata attributes provided by Twitter API, such as information about who and when posted it, in what language, and how many other users engaged with it (retweeted or favorited). For the full list of available metadata elements for a Tweet object, see the Twitter API documentation.
As noted earlier, in addition to the metadata provided by Twitter API, we have also used Perspective API (via Communalytic) to calculate and assign toxicity scores to each tweet in the dataset. See our online tutorial on how to run a toxicity analysis in Communalytic.
This process assigns 8 additional values to each tweet, representing the following scores (ranging from 0 to 1):
- Toxicity score represents the degree to which the comment is rude, disrespectful, or unreasonable.
- Severe Toxicity score represents how hateful, aggressive, and disrespectful the comment is.
- Profanity score indicates if swear words or other profane language is used.
- Identity Attack score indicates if a post contains hateful language targeting someone because of their identity.
- Insult score helps to identify insulting or inflammatory posts.
- Threat score represents the degree to which a post displays an intention to inflict pain or violence against an individual or group.
- Sexually Explicit score indicates if a post contains references to sexual acts, body parts, or other lewd content.
- Flirtation score indicates if a post contains language commonly used in pickup lines, compliments regarding appearance, or subtle sexual innuendos.
For more information about how these scores are calculated and evaluated, see the Perspective API documentation. The API currently supports the analysis in 7 different languages (English, Spanish, French, German, Portuguese, Italian, Russian).
Since the majority of posts in our dataset (83%, 247,975 of 298,172) were written in English (as detected by Twitter), the subsequent analysis will be based only on English posts for consistency of the results.
To further enrich our dataset, we used the twarc library to collect information about the availability status of each tweet 12 days after the original data collection. The purpose of this was to identify whether any of the tweets or users originally included in the dataset are still available or if they have been removed by the platform for violation of its policies. After running this script, a new attribute called tweet_status was added to the dataset with the following possible values:
- user_suspended – the account is suspended by Twitter;
- user_protected – the account’s privacy setting has been changed to ‘protected’;
- user_deleted – the account has been deleted, presumably by the user;
- tweet_blocked – the tweet has been blocked by Twitter;
- tweet_deleted – the tweet has been deleted;
- tweet_ok – the tweet is still available.
Table 1 shows the counts of tweets based on their availability status, with the majority of English tweets being still available (96%, 238,272 out of 247,975).
To explore the range of toxicity score values in the dataset, we built eight histograms to visualize a distribution of values for each toxicity score. From Figure 2, we can see that values for all eight scores are skewed to the left, with the majority of posts having values of less than 0.5. So, even though we expected a higher level of toxicity in replies to Trump’s tweet due to the highly polarized political environment leading up to the 2020 US Presidential election, this exploratory analysis suggests that the majority of replies are not as toxic as we expected.
While Perspective API calculates 8 different scores representing different aspects of toxicity, some of them might be highly related, for example ‘toxicity’ and ‘severe toxicity’. To find out to what extent the toxicity scores are correlated with each other, we can use a correlation matrix as shown in Figure 3. For each pair of toxicity scores, the matrix represents correlation values between 0 to 1, where 0 corresponds to not correlated and 1 corresponds to highly correlated. The values are represented in the correlation matrix in shades of red: from light red (values closer to 0) to the dark red (values closer to 1).
As shown in Figure 3, the following scores are highly correlated with each other (correlation values of 0.7 or higher): toxicity, severe toxicity, profanity, identity attack, and insult. The ‘threat’ and ‘sexually explicit’ scores moderately correlate with the rest of the scores (correlation values between 0.3 and 0.7). This means that in general, a high value in any one of these scores will correspond to a high value in the other scores, except for the ‘flirtation’ score which captures a somewhat different aspect of online exchanges.
For the purposes of our exploratory analysis, we will only examine the ‘toxicity’ score because it can be used as a proxy for the majority of the scores provided by Perspective API. (Note: the correlation results are likely dataset/domain specific, so we suggest checking for multicollinearity among the toxicity scores when analyzing a different dataset.)
Twitter is generally proactive in detecting toxic tweets and taking actions against users, such as suspending their account or individual tweets, if they violate its rules and policies.
One question that we want to investigate in this post is how likely Twitter is to take action against those who post toxic messages (by either suspending an account or blocking a tweet). In other words, are blocked tweets (including tweets posted by accounts that are now suspended) more toxic on average than tweets that are still available? To investigate this, we looked at the average toxicity scores in relation to the availability status of a tweet or account.
The bar chart (Figure 4) shows the average toxicity values for tweets with different availability statuses as provided by Twitter API about 12 days after they were originally posted. Tweets that are still available have the lowest average toxicity value of 0.34, while tweets that have been blocked by the platform have the average toxicity value of 0.82 which is twice as large as the value for the other categories. This suggests that the platform indeed acts on tweets that are especially toxic by blocking them. However, since only a small proportion of tweets, 691 tweets, has been blocked by the platform, this finding must be taken with caution.
It is important to note that ANOVA (Analysis of Variance) can be used to test for differences across means more formally (see examples: here and here; also read this post to learn more about how to handle data that is not normally distributed). This more formal analysis is outside the scope of this post.
We also expected that tweets posted by now suspended accounts would have much higher values of toxicity relative to tweets that are still available. However, the difference was only marginal (0.4 for tweets by suspended accounts versus 0.34 for tweets that are still available, see Figure 4). This is likely because users can be suspended not only because they might be attacking others by posting toxic tweets, but also because they violated other community norms, such as copyright or impersonation policies. Thus, toxicity scores are not the only variables that may predict if an account would be suspended (and vice versa). Furthermore, since toxicity scores are only calculated based on the textual part of a tweet, it does not account for potentially toxic media files or URLs attached to the tweet.
In this post, we conducted an exploratory toxicity analysis of a Twitter dataset consisting of 298,172 replies to Donald Trump’s tweet announcing his COVID-19 diagnosis. We found that most of the toxicity scores produced by Perspective API are highly correlated. We also found that tweets that are blocked by Twitter have, on average, higher toxicity scores than tweets that are either still available or posted by suspended or protected accounts. Interestingly, there was no clear connection between posting toxic tweets and an account being suspended.
If you are interested in exploring this dataset on your own and practicing your data science skills, you can retrieve our dataset from Dataverse. The dataset contains the toxicity scores and tweet status values that we added for this analysis; however, following Twitter’s API policy, we stripped metadata associated with each tweet except TweetId (unique identifier). So, if you’d like to examine potential relationships between other metadata elements, you would need to recollect the original tweets using a tool like DocNow’s Hydrator first. The only downside of this approach is that tweets that have been blocked or deleted will not be recollected. To help you get started, we also shared our Python script here.
Happy Data Exploration!
*By Anatoliy Gruzd and Shahnawaz Attarwala with editorial contributions from Alyssa Saiphoo.
- Matplotlib Python library is used for plotting graphs
- Sample Python script for exploratory data analysis
- Exploratory Data Analysis with PySpark on Databricks
- Example of using twarc library