---
title: "Data Analysis of Trump Tweets"
author: "Nathan Taback"
date: "October 5, 2017"
output:
  html_document: default
  html_notebook: default
---

```{r,cache=TRUE,echo=FALSE,warning=FALSE,message=FALSE}
knitr::opts_chunk$set(message=FALSE,warning=FALSE)
```


# Trump and Twitter

Donald Trump likes to tweet a lot.  Some tweets have an angry sentiment or contain insults, and some are not.  Several journalists have claimed that Trump sends tweets from a [Samsung Galaxy](https://www.theatlantic.com/politics/archive/2017/03/a-bot-that-detects-when-donald-trump-is-tweeting/521127/) when he is [insulting people, places, and things](https://www.nytimes.com/interactive/2016/01/28/upshot/donald-trump-twitter-insults.html?mcubz=0&_r=0), and from other devices, such as an iPhone, when he is not.  It seems plausible that Trump's staff members, like many politicians, post tweets to his account.  Do tweets that Trump write have an angry sentiment compared to tweets written by his staff? 


This analysis is based on David Robinson's post [Trump's Android and iPhone tweets, one year later.](http://varianceexplained.org/r/trump-followup/)

# Data 

## Data Source

Trump's last tweet from an [Android was on March 25, 2017](https://www.cnbc.com/2017/03/29/donald-trump-apple-iphone-android-unsecured.html).  

The data source used for this report was curated by Brendan Brown [archive of Trump's twitter posts.](http://www.trumptwitterarchive.com).

All Trump's tweets from Browns's [archive of Trump's twitter posts.](http://www.trumptwitterarchive.com) were downloaded on September 28, 2017. The Tweets included in the data range from Trump's first tweet on December 11, 2012 to the last tweet using his Android on March 25, 2017.


```{r,cache=TRUE,warning=FALSE,message=FALSE,echo=FALSE}
library(jsonlite)
library(tidyverse)
library(stringr)
library(lubridate)
url <- "http://utstat.toronto.edu/~nathan/teaching/sta4002/Class4/trumptweets.JSON"
trumptweets <- fromJSON(url)
tweets <- trumptweets %>% select(source, text, created_at,id_str) %>% 
  mutate(created_at = parse_date_time(created_at, "a b! d! H!:M!:S! z!* Y!")) %>% 
  filter(created_at < "2017-03-26") %>%
  mutate(source=ifelse(str_detect(source,"iPhone"),"iPhone",                    ifelse(str_detect(source,"Android"),"Android","NA"))) %>%
  filter(source %in% c("iPhone", "Android"))

```

# Exploring the Data

In this section the data will be explored with a focus on assessing the evidence that the device used to tweet has a different usage pattern.

Tweets from the Android are sent at different times of day compared to the iPhone.  The Android rarely sends links or pictures while the iPhone sends links and pictures.


```{r,warning=FALSE,message=FALSE,echo=FALSE}
library(lubridate)
library(scales)
library(tidyverse)
tweets %>% count(source, hour = hour(with_tz(created_at, "EST"))) %>%
  mutate(percent = n / sum(n)) %>%
  ggplot(aes(hour, percent, color = source)) +
  geom_line() +
  scale_y_continuous(labels = percent_format()) +
  labs(x = "Hour of day (EST)",
       y = "% of tweets",
       color = "")
```


```{r, ,warning=FALSE,message=FALSE,echo=FALSE}
library(tidyverse)
library(stringr)
tweet_picture_counts <- tweets %>% filter(!str_detect(text, '^"')) %>% count(source, picture = ifelse(str_detect(text, "t.co"), "Picture/link", "No picture/link"))

ggplot(tweet_picture_counts, aes(source, n, fill = picture)) + geom_bar(stat = "identity", position = "dodge") + labs(x = "", y = "Number of tweets", fill = "")
```


## Comparison of Words

Individual words that comprise Trump's tweets are analyzed in this section.   In other words, Trump's tweets can be [tokenized](http://text-processing.com/demo/tokenize/) with [stop words](https://en.wikipedia.org/wiki/Stop_words) removed.

The plot below shows the twenty most frequent words appearing in his tweets during the study period. 

```{r,cache=TRUE,warning=FALSE,message=FALSE,echo=FALSE}
library(tidytext)
library(tidyverse)
library(stringr)

# tokenize to include @ and #

reg <- "([^A-Za-z\\d#@']|'(?![A-Za-z\\d#@]))"

tweet_words <- tweets %>% filter(created_at < "2017-03-26") %>% filter(!str_detect(text, '^"')) %>% mutate(text = str_replace_all(text, "https://t.co/[A-Za-z\\d]+|&amp;", "")) %>% unnest_tokens(word, text, token = "regex", pattern = reg) %>% filter(!word %in% stop_words$word, str_detect(word, "[a-z]"))

#head(tweet_words)

#tweet_words %>% count(word) %>% top_n(50) %>% ggplot(aes(word,n))+geom_col()+coord_flip()+labs(x="Word",y="Number of times word ocurres in a Tweet")

tweet_words %>% count(word) %>% mutate(word=reorder(word,n)) %>% top_n(20) %>% ggplot(aes(word,n))+geom_col()+coord_flip()+labs(x="Word",y="Number of times word ocurres in a Tweet")
```

Which words are more commonly used when the source is Android versus iPhone?  One measure that can be used to compare the rates of words tweeted from an Android versus iPhone is the log-odds ratio. 

$$\log\left(\frac{\frac{\#\text{ times word from Android }+1}{\text{Total Android Words}}}
            {\frac{\#\text{ times word from iPhone }+1}{\text{Total iPhone Words}}} \right) $$


This compares the odds of a word being tweeted from an Android compared to an iPhone.

The plot below shows the log-odds ratio for the top twenty words tweeted from an Android versus iPhone provided that the word had been tweeted at least five times. Words with a positive log-odds ratio imply that the word is tweeted at a higher rate on Android versus iPhone, and a negative log-odds ratio means that the word is tweeted at a higher rate on iPhone versus Android.   

```{r,,warning=FALSE,message=FALSE, echo=FALSE}
android_iphone_ratios <- tweet_words %>%
  count(word, source) %>%
  filter(sum(n) >= 5) %>%
  spread(source, n, fill = 0) %>%
  ungroup() %>%
  mutate_each(funs((. + 1) / sum(. + 1)), -word) %>%
  mutate(logratio = log(Android / iPhone)) %>%
  arrange(desc(logratio))

#head(android_iphone_ratios)

android_iphone_ratios %>%
  group_by(logratio > 0) %>%
  top_n(15, abs(logratio)) %>%
  ungroup() %>%
  mutate(word = reorder(word, logratio)) %>%
  ggplot(aes(word, logratio, fill = logratio < 0)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  ylab("Android / iPhone log ratio") +
  scale_fill_manual(name = "", labels = c("Android", "iPhone"),
                    values = c("red", "lightblue"))
```



## Sentiment Analysis of Words used in Trump's Tweets

> [The NRC Emotion Lexicon](http://saifmohammad.com/WebPages/NRC-Emotion-Lexicon.htm) is a list of English words and their associations with eight basic emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive). The annotations were manually done by crowdsourcing. 

Words can be classified into two sentiments (positive or negative) and eight emotions (sentiments: anger, anticipation, disgust, fear, joy, sadness, surprise, trust).  Words can have a sentiment association and several emotional associations.  


Several words and thier NRC classification is shown in the table below.  Abandon, for example, falls into several categories.

```{r,echo=FALSE}
library(tidytext)
knitr::kable(sentiments %>% filter(lexicon=="nrc") %>% select(-score,-lexicon) %>% head())
```


The bar chart below shows the distribution of sentiment and emotions for all the NRC categories for Android and iPhone.

The percentage of words in each category of sentiment/emotion was calculated as:

$$\text{Percentage of Words} = \frac{\#\text{ words in Sentiment/Emotion tweeted using Source}}{\text{Total number of words tweeted using Source}} \times 100 $$

```{r,cache=TRUE,,warning=FALSE,message=FALSE,echo=FALSE}
nrc <- sentiments %>%
  filter(lexicon == "nrc") %>%
  dplyr::select(word, sentiment)

sources <- tweet_words %>%
  group_by(source) %>%
  mutate(total_words = n()) %>%
  ungroup() %>%
  distinct(id_str, source, total_words)

by_source_sentiment <- tweet_words %>%
  inner_join(nrc, by = "word") %>%
  count(sentiment, id_str) %>%
  ungroup() %>%
  complete(sentiment, id_str, fill = list(n = 0)) %>%
  inner_join(sources) %>%
  group_by(source, sentiment, total_words) %>%
  summarize(words = sum(n)) %>%
  ungroup()

#head(by_source_sentiment)

by_source_sentiment %>% group_by(source) %>% mutate(rate=words/total_words) %>% ggplot(aes(x=reorder(sentiment,-rate),y=rate))+geom_col(stat="identity",position = "dodge",aes(fill=source))+
  scale_y_continuous(labels = percent_format()) + coord_flip()+
  labs(x = "Sentiment/Emotion", y = "Percentage of words")
```



# Statistical Analysis

## Comparing Rates of Words Categorized using the NRC Lexicon

One simple statistical model to compare word sentiments and emotions in Android versus iPhone is a Poisson regression.

The dependent variable $Y_i,\, i=1,2$ is the count of words within a sentiment/emotion category for each source (2 sources) with $n_i$ total words from the source.  The covariate of interest $x_i$ is source of the tweet:

$$ x_{i} =\left\{
	\begin{array}{ll}
		1  & \mbox{if } i^{th}\text{word from Android} \\
		0 & \mbox{if } i^{th} \text{word from iPhone}
	\end{array}
\right. $$

The counts can be modelled as a Poisson random variable.  A generalized linear model for word count is:

$$E\left( Y_i\right)=\mu_i=n_i\theta_i,\, Y_i \sim Poisson(\mu_i), $$

where $\theta_i=\exp\left(x_i\beta\right).$ $\mu_i$ is the average number of Trump tweets with a certain sentiment/emotion out of all the tweets sent from one of the sources during the time period December 12, 2012 and September 28, 2017. The natural link function is:

$$\log\left(\mu_i \right)=log(n_i)+x_i\beta. $$

```{r,eval=FALSE,echo=FALSE}
tweets[order(as.Date(tweets$created_at)),]
```


```{r,cach=TRUE,,warning=FALSE,message=FALSE,echo=FALSE}
library(broom)

modeldat <- by_source_sentiment 
modeldat$source <- relevel(as.factor(modeldat$source),ref="iPhone")

#anger
preg1 <- glm(words~source+offset(log(total_words)),data=modeldat,family=poisson,subset = sentiment=="anger")
#tidy(preg1,conf.int = T)[2,6]
#exp(coefficients(preg1)[2])

#anticipation
preg2 <- glm(words~source+offset(log(total_words)),data=modeldat,family=poisson,subset = sentiment=="anticipation")
#tidy(preg2,conf.int = T)
#exp(coefficients(preg2)[2])
```

The parameter estimate for $\beta$ is an estimate of the rate ratio 
$$\log \left(\frac{E(Y_i|x_i=\text{Android})}{E(Y_i|x_i=\text{iPhone})} \right).$$  

For example, $\exp(\beta)$ is the percent increase in a word being tweeted from an Android versus an iPhone. The percent increase in tweets with words related to anticipation is `r round(exp(coefficients(preg2)[2])%%1*100)`%

This is identical to conducting a hypothesis test of $H_0:\lambda_1=\lambda_2$.  These hypotheses can be evaluated in R using `poisson.test`.  A plot of the 95% confidence intervals is shown below.


```{r,warning=FALSE,message=FALSE, echo=FALSE}
#Estimate the ratio of words for each sentiment and emotion among Android versus iPhone tweets.
sentiment_differences <- by_source_sentiment %>%
  group_by(sentiment) %>%
  do(tidy(poisson.test(.$words, .$total_words)))

#sentiment_differences[c(1,2,4,6,7)]

library(scales)
sentiment_differences %>%
  ungroup() %>%
  mutate(sentiment = reorder(sentiment, estimate)) %>%
  mutate_each(funs(. - 1), estimate, conf.low, conf.high) %>%
  ggplot(aes(estimate, sentiment)) +
  geom_point() +
  geom_errorbarh(aes(xmin = conf.low, xmax = conf.high)) +
  scale_x_continuous(labels = percent_format()) +
  labs(x = "% increase in Android relative to iPhone",
       y = "Sentiment/Emotion")
```

## Comparing AFINN Sentiment Score

To evaluate the sensitivity of lexicon choice, an analysis was conducted using the AFINN lexicon.  The [AFINN sentiment library](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6010) words have been manually rated for valence with an integer between minus five (negative) and positive five (positive).  

Tweets were tokenized into words.  If a word is in the AFINN lexicon then it will be scored.  The average score for each is then calculated.    

A side-by-side boxplot of the distributions of AFINN scores by device, and the results of a two-sample t-test of the difference is shown below.

```{r,echo=FALSE,message=FALSE,warning=FALSE}
library(broom)
tweet_afinn <- tweet_words %>% inner_join(get_sentiments("afinn")) %>% 
  group_by(id_str) %>% 
  mutate(avg_sent=mean(score),hour = hour(with_tz(created_at, "EST"))) %>% 
  select(-word,-score) %>% distinct()

#head(tweet_afinn)

tweet_afinn %>% ggplot(aes(source,avg_sent))+geom_boxplot()+
  labs(x = "Tweet Source",
       y = "AFINN Score")

#t.test(tweet_afinn$avg_sent[tweet_afinn$source=="Android"])

#t.test(tweet_afinn$avg_sent[tweet_afinn$source=="iPhone"])
  
ttest_res <- tweet_afinn %>% t.test(avg_sent~source,data=.)

ttest_dat <- data_frame(round(ttest_res$estimate[1]-ttest_res$estimate[2],2),ttest_res$p.value,round(ttest_res$conf.int[1],2),round(ttest_res$conf.int[2],2)) 

colnames(ttest_dat) <- c("Difference Mean AFINN (Android - iPhone)","P-value","Lower 95% CI","Upper 95% CI")

ttest_dat %>% knitr::kable()

```

The boxplot and t-test show that tweets sent from an iPhone have a significantly higher sentiment compared to tweets sent from an Android. 

# Limitations

A few notable limitations are:

- All of the analyses assumes that Trump tweets from an Android and his staff tweets from an iPhone during the study period.

- The Poisson regression analysis using rates derived from the NRC lexicon evaluate individual words instead of the entire tweet.

- The t-test using the mean AFINN scores score an entire tweet only if a word is in the AFINN lexicon.

- There is no available literature on a meaningful difference between AFINN scores.  

- Links and images were removed from tweets prior to measuring sentiment.  Removing links and images removes information about the sentiment.

NB: Ideally this section would also describe how the limitations effect the analysis.

# Conclusions

Negative words and words associated with disgust, sadness, anger, and fear are tweeted more frequently from an Android versus iPhone during the study period.  Positive words and words associated with surprise, joy, anticipation, and trust are tweeted at a higher rate from Android versus iPhone, although the magnitude of the percent increase is less compared to negative and angry words.  The percent increase of negative and angry words from the Android device are significantly greater compared to positive words.  

Trump's staffs' tweets have a positive sentiment compared to Trump's tweets. Overall, Trump's tweets have a neutral sentiment, and his staffs' tweets have a positive sentiment.