Everytime you release a product or service you want to receive feedback from users so you know what they like and what they don’t. Sentiment Analysis can help you. I will show you how to create a simple application in R and Shiny to perform Twitter Sentiment Analysis in real-time. I use RStudio.
We will be able to see if they liked our products or not. Also, we will create a wordcloud to find out why they liked it and why not.
First, I will create a Shiny Project. To learn how to create a Shiny apps you might read this tutorial by Teja Kodali and another tutorial by Aaron Gowins.
Then, in the ui.R file, I put this code:
shinyUI(fluidPage(
titlePanel("Sentiment Analysis"), #Title
textOutput("currentTime"), #Here, I show a real time clock
h4("Tweets:"), #Sidebar title
sidebarLayout(
sidebarPanel(
dataTableOutput('tweets_table') #Here I show the users and the sentiment
),
Show a plot of the generated distribution:
mainPanel(
plotOutput("distPlot"), #Here I will show the bars graph
sidebarPanel(
plotOutput("positive_wordcloud") #Cloud for positive words
),
sidebarPanel(
plotOutput("negative_wordcloud") #Cloud for negative words
),
sidebarPanel(
plotOutput("neutral_wordcloud") #Cloud for neutral words
)))))
Here, I will show a title, the current time, a table with Twitter user name, a bar graph and wordclouds. Also you have to put your consumer key and secret (replace xxxxxxxxxx). You will have to create and application in Twitter Developers site and then extract this info.
Now, I will create the server side:
library(shiny)
library(tm)
library(wordcloud)
library(twitteR)
shinyServer(function(input, output, session) {
setup_twitter_oauth(consumer_key = "xxxxxxxxxx", consumer_secret = "xxxxxxxxxxxx")
token <- get("oauth_token", twitteR:::oauth_cache)
token$cache()
output$currentTime <- renderText({invalidateLater(1000, session)
paste("Current time is: ",Sys.time())})
observe({
invalidateLater(60000,session)
count_positive = 0
count_negative = 0
count_neutral = 0
positive_text <- vector()
negative_text <- vector()
neutral_text <- vector()
vector_users <- vector()
vector_sentiments <- vector()
tweets_result = ""
tweets_result = searchTwitter("word-to-find-in-twitter")
for (tweet in tweets_result){
print(paste(tweet$screenName, ":", tweet$text))
vector_users <- c(vector_users, as.character(tweet$screenName));
if (grepl("lindo", tweet$text, ignore.case = TRUE) == TRUE | grepl("Wonderful", tweet$text, ignore.case = TRUE) | grepl("Awesome", tweet$text, ignore.case = TRUE)){
count_positive = count_positive + 1
print("positivo")
vector_sentiments <- c(vector_sentiments, "Positive")
positive_text <- c(positive_text, as.character(tweet$text))
} else if (grepl("Boring", tweet$text, ignore.case = TRUE) | grepl("I'm sleeping", tweet$text, ignore.case = TRUE)) {
count_negative = count_negative + 1
print("negativo")
vector_sentiments <- c(vector_sentiments, "Negative")
negative_text <- c(negative_text, as.character(tweet$text))
} else {
count_neutral = count_neutral + 1
print("neutral")
vector_sentiments <- c(vector_sentiments, "Neutral")
neutral_text <- c(neutral_text, as.character(neutral_text))
}
}
df_users_sentiment <- data.frame(vector_users, vector_sentiments)
output$tweets_table = renderDataTable({
df_users_sentiment
})
output$distPlot <- renderPlot({
results = data.frame(tweets = c("Positive", "Negative", "Neutral"), numbers = c(count_positive,count_negative,count_neutral))
barplot(results$numbers, names = results$tweets, xlab = "Sentiment", ylab = "Counts", col = c("Green","Red","Blue"))
if (length(positive_text) > 0){
output$positive_wordcloud <- renderPlot({ wordcloud(paste(positive_text, collapse=" "), min.freq = 0, random.color=TRUE, max.words=100 ,colors=brewer.pal(8, "Dark2")) })
}
if (length(negative_text) > 0) {
output$negative_wordcloud <- renderPlot({ wordcloud(paste(negative_text, collapse=" "), random.color=TRUE, min.freq = 0, max.words=100 ,colors=brewer.pal(8,"Set3")) })
}
if (length(neutral_text) > 0){
output$neutral_wordcloud <- renderPlot({ wordcloud(paste(neutral_text, collapse=" "), min.freq = 0, random.color=TRUE , max.words=100 ,colors=brewer.pal(8, "Dark2")) })
}
})
})
})
Here a screenshot of the shiny app we created:

It's a really simply code, not complex at all. The purpose of it is just for testing and so you guys can practice R language. If you have questions just let me know.
Listening on http://127.0.0.1:7944
Warning: Error in shinyServer: argument “output” is missing, with no default
50: shinyServer [#4]
Error in shinyServer(function(input, output, session) { :
argument “output” is missing, with no default
This issue is occur when I run this code.
Hi, the article is pretty good for beginners. I realized I wasn’t able to get the application to run because it was behind a firewall in an enterprise network. However, it worked with my home network.
Kindly help me understand the what does “Vector Users” mean? Which user handles does it fetch tweets from? Also, the sentiment analysis always gives me a Neutral outcome with no WordCloud for the same. Awaiting for your response.
Good tutorial, See I have a question can you take a keyword from user in an input field and search tweets on that keyword and then analyse all the things and plot the histograms.Is that possible?
Error in curl::curl_fetch_memory(url, handle = handle) :
Peer certificate cannot be authenticated with given CA certificates
How to handle this error
If I have a list of pos words and neg words as txt files, where can I scan this in the code. Right now, I am just getting all neutral tweets so want to define the parameters to be more specific
hola no puedo cargar debido a que tengo este error
> runApp(“Twitter”)
Listening on http://127.0.0.1:5509
Loading required package: tm
Loading required package: NLP
Loading required package: wordcloud
Loading required package: RColorBrewer
Loading required package: twitteR
Note: the specification for S3 class “integer64” in package ‘bit64’ seems equivalent to one from package ‘jsonlite’: not turning on duplicate class definitions for this class.
[1] “Using browser based authentication”
Use a local file to cache OAuth access credentials between R sessions?
1: Yes
2: No
Warning: Error in init_oauth1.0: Unauthorized (HTTP 401).
Stack trace (innermost first):
50:
49: stop
48: stop_for_status
47: init_oauth1.0
46: self$init_credentials
45: public_bind_env$initialize
44: Token1.0$new
43: oauth1.0_token
42: token_func
41: setup_twitter_oauth
40: server [/home/indira/Dropbox/Maestria Ciencia de Datos/TFM/Dev/R/shiny/Twitter/server.R#19]
1: runApp
Error in init_oauth1.0(self$endpoint, self$app, permission = self$params$permission, :
Unauthorized (HTTP 401).
did you solved this error?
because I am also getting same error
We just can analyse 25 records?
tweets_result = searchTwitter(“word-to-find-in-twitter”, n=1500). You can add “n=” option (max value is 1500).
There is a mistake in this line :
neutral_text <- c(neutral_text, as.character(neutral_text))
for the neutral worcloud, it is necessary to replace by
neutral_text <- c(neutral_text, as.character(tweet$text))
Thanks for this share Diego 🙂
Oh tks, I see this I downloaded the twitterR pdf… 😀 TKS TKS <3
Thanks Diego! It would be more helpful if you can explain command by command in comments.
Check out the brackets/parentheses on the last few lines on the server.R. Currently you end up with unmatched parens etc.
Hi Michael, thanks for your comment. It’s updated now. Thanks!