Analiza danych twitterowych
Wstep
Projekt dotyczy danych wydobytych z popularnej platformy twitter.com poprzez API, na podstawie których przeprowadzone zostaną działania z zakresu data mining’u takie jak czyszczenie danych, wizualizacja, czy analiza sentymentu. Analiza sentymentu odbędzie się przy pomocy biblioteki tidytext, posiadającej dwa słowniki “nrc” oraz “bing”. Twitter oprócz bycia jednym z najbardziej popularnych social mediów, to również zbiór ogromnej ilosci danych, pozwalających na wgląd w zachowanie opinii publicznej, stając się jednym ze źródeł informacji m.in. dla przedsiębiorstw.
Pozyskanie danych z pakietem rtweet
Pierwszym krokiem jest zalaczenie niezbednych do analizy bibliotek.
library(rtweet)
library(ROAuth)
library(tm)
library(wordcloud)
library(plyr)
library(RColorBrewer)
library(dplyr)
library(ggplot2)
library(ggthemes)
library(wordcloud2)
library(lubridate)
library(ggthemes)
library(tidytext)
library(httr)
library(syuzhet)
library(plotly)
library(patchwork)
library(ape)
library(tidyverse)
library(cluster)
library(factoextra)
library(dendextend)
library(textdata)Pakiet “rtweet” umożliwia szybkie i sprawne gromadzenie oraz porzdkowanie danych z platformy twitter.com za posrednictwem Rest API, ktore mozemy pozyskac ze strony https://developer.twitter.com/en/apply-for-access. Najpierw należy utworzyć konto oraz wypełnić formularz zgłoszeniowy, który będzie zawierał informacje o tym w jakim celu chcemy ewentualnie wykorzystać pozyskane dane.
Powinnismy uzyskac następujące dane: * Consumer key * Consumer Secret * Access Token * Access Secret
Utworzenie tokenu oraz pobranie danych
Poprzez utworzenie tokenu z otrzymanymi wcześniej parametrami dokonujemy uwierzytelniania oraz połączenia z twitterem.
W zależności od potrzeb możemy wyszukać określone słowo, hashtag za pomocą funkcji search_twitter , bądź określonego konta za pomocą get_timeline. W naszym projekcie do analizy wybrano konto Elona Muska. Limit ilości tweetów wynosi 3200.
token <- create_token (
app = "XXXXXXXXXXX",
consumer_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
consumer_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
access_token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
access_secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')## <Token>
## <oauth_endpoint>
## request: https://api.twitter.com/oauth/request_token
## authorize: https://api.twitter.com/oauth/authenticate
## access: https://api.twitter.com/oauth/access_token
## <oauth_app> WizualizacjaR
## key: I8xaevANVuoHedPoxGfdfuHy6
## secret: <hidden>
## <credentials> oauth_token, oauth_token_secret
## ---
Wstępna analiza danych twitterowych
Podzielono tweetty na 3 podgrupy:
- te, których twórcą jest Elon Musk (organic)
- te, które Elon Musk podał dalej (retweets)
- te, na które Elon Musk odpowiedział (replies)
ElonMuskTweets_organic <- ElonMuskTweets[ElonMuskTweets$is_retweet==FALSE, ]
ElonMuskTweets_organic <- subset(ElonMuskTweets_organic, is.na(ElonMuskTweets_organic$reply_to_status_id))
ElonMuskTweets_organic <- ElonMuskTweets_organic %>% arrange(-favorite_count)
ElonMuskTweets_organic <- ElonMuskTweets_organic %>% arrange(-retweet_count)
ElonMuskTweets_retweets <- ElonMuskTweets[ElonMuskTweets$is_retweet==TRUE,]
ElonMuskTweets_replies <- subset(ElonMuskTweets, !is.na(ElonMuskTweets$reply_to_status_id))df <- data.frame(
category=c("Organic", "Retweets", "Replies"),
count=c(c(417, 2554, 228))
)
df$fraction = df$count / sum(df$count)
df$percentage = df$count / sum(df$count) * 100
df$ymax = cumsum(df$fraction)
df$ymin = c(0, head(df$ymax, n=-1))
Segmentation_of_tweets <- paste(df$category, df$percentage, "%")
ggplot(df, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=Segmentation_of_tweets)) +
geom_rect() +
coord_polar(theta="y") +
xlim(c(2, 4)) +
theme_minimal() +
theme(legend.position = "right") + labs(title = "Podzial na rodzaje postów zamieszczanych na Twitter.com", caption = "Twitter.com")colnames(ElonMuskTweets)[colnames(ElonMuskTweets) == "screen_name"] <- "Twitter_Account"
ts_plot(group_by(ElonMuskTweets, Twitter_Account), "year") +
theme_minimal() +
theme(plot.title = element_text(face = "bold")) +
labs(
x = NULL,
y = NULL,
title = "Czestotliwosc twittow Elona Muska",
subtitle = "Zagregowana suma",
caption = "Twitter.com"
)## `summarise()` ungrouping output (override with `.groups` argument)
ElonMusk_app <- subset(ElonMusk_app, count > 11)
data <- data.frame(
category=ElonMusk_app$source,
count=ElonMusk_app$count
)
data$fraction = data$count / sum(data$count)
data$percentage = data$count / sum(data$count) * 100
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
Source <- paste(data$category, data$percentage, "%")
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=Source)) +
geom_rect() +
coord_polar(theta="y") + # Try to remove that to understand how the chart is built initially
xlim(c(2, 4)) +
theme_void() +
theme(legend.position = "right")+
labs(
x = NULL, y = NULL,
title = "Podzial ze wzgledu na sposob udostepniania postu",
caption = "Twitter.com"
)ElonMuskTweets$date <- day(ElonMuskTweets$created_at)
ElonMuskTweets$hour <- hour(ElonMuskTweets$created_at)
theme_set(theme_tufte())
ggplot(ElonMuskTweets, aes(x = hour)) +
geom_density(color = "tomato3", fill = "tomato3", alpha=0.4) +
labs(title ="Wykres gestosci", subtitle="Czestosc oznaczen na twitterze", caption="Source: Twitter.com") +
xlab("Godziny") +
ylab("Gestosc oznaczen na twitterze")Czyszczenie danych
ElonMuskTweets$text <- gsub("@[[:alpha:]]*","", ElonMuskTweets$text) #usuwamy wszystkich uzytkownikow
Corpus <- Corpus(VectorSource(ElonMuskTweets$text))
Corpus <- tm_map(Corpus, content_transformer(tolower))
removeURL <- function(x) gsub("http[^[:space:]]*", "", x)
Corpus <- tm_map(Corpus, content_transformer(removeURL))
removeNumPunct <- function(x) gsub("[^[:alpha:][:space:]]*", "", x)
Corpus <- tm_map(Corpus, content_transformer(removeNumPunct))
Stopwords <- c(setdiff(stopwords('english'), c("r", "big")),
"use", "see", "used", "via", "amp", "rt", "RT","by","youve" , "bbc")
Corpus <- tm_map(Corpus, removeWords, Stopwords)
Corpus <- tm_map(Corpus, stripWhitespace)
Corpus <- tm_map(Corpus,removeNumbers)
Corpus <- tm_map(Corpus,removePunctuation,preserve_intra_word_dashes = TRUE)
inspect(Corpus[1:10])## <<SimpleCorpus>>
## Metadata: corpus specific: 1, document level (indexed): 0
## Content: documents: 10
##
## [1] exactly
## [2] gary snail still winning gaining himher
## [3] embrace tunnels
## [4] tunnels solution traffic can many levels want usable tunnel depth far exceeds tallest buildings work even new york beijing
## [5] just guess probably mid teens booster stacking orbital pad likely limiting factors well build several ships just improve production system
## [6] pretty accurate simulation although sn will raptors sn craters sn sn close behind high production rate allows fast iteration
## [7] couldnt agree major software improvements already place extend life coming
## [8] definitely smartwatches phones yesterdays technology neuralinks future
## [9] feed seems like make whole outfit material
## [10] ancient greece committed suicide nobody digs grave better
Zliczanie występowania słów
## [1] 5754 3199
ap.v <-sort(rowSums(ap.m),decreasing=TRUE)
ap.d <-data.frame(word=names(ap.v),freq=ap.v)
freq.terms <- findFreqTerms(ap.tdm, lowfreq = 10)
term.freq <- rowSums(as.matrix(ap.tdm))
term.freq <- subset(term.freq, term.freq >= 10)
df <- data.frame(term = names(term.freq), freq = term.freq)
df_4 <-df[order(-df$freq),]
y <- df_4 %>% top_n(10)## Selecting by freq
Wizualizacja oczyszczonych i zliczonnych danych
ggplot(y, aes(x = term, y = freq)) + geom_bar(stat = "identity", fill="steelblue") +
xlab("Slowa") + ylab("Ilosc wystapien") + labs(title = 'TOP 20 SLOW',
subtitle ='Slowa, ktore najczesciej wystepuja w postach Elona Muska' , caption = "Twitter.com") + coord_flip() +
theme(axis.text = element_text(size = 10))## Selecting by freq
pal2 <- brewer.pal(8,"Dark2")
wordcloud(w$word,w$freq,scale=c(8,.2),min.freq=3,
max.words=Inf, random.order=FALSE,rot.per=.15,colors=pal2)Analiza sentymentu
Analiza sentymentu jest jedna z rodzajow analizy tekstu. Dzięki niej możemy sklasyfikować przeróżne dane tekstowe otrzymując informacji o nacechowaniu całej wypowiedzi oraz jej pojedynczej składowej. Stosowana jest do określania ludzkich opinii, odczuć oraz postaw wobec produktów, usług, organizacji, co daje możliwość wykorzystania jej w analizie społecznej ekonomicznej oraz biznesowej. W analizie skorzystamy z dwóch słowników pochodzących z pakietu tidytext “bing” oraz “nrc”.
Słownik bing
Słownik kategoryzuje słowa w kategoriach pozytywnych i negatywnych.
## # A tibble: 6,786 x 2
## word sentiment
## <chr> <chr>
## 1 2-faces negative
## 2 abnormal negative
## 3 abolish negative
## 4 abominable negative
## 5 abominably negative
## 6 abominate negative
## 7 abomination negative
## 8 abort negative
## 9 aborted negative
## 10 aborts negative
## # ... with 6,776 more rows
colnames(df) <-c("word","n")
df %>%
inner_join(get_sentiments("bing"), by = "word") %>%
group_by(sentiment) %>%
ungroup() %>%
mutate(word = reorder(word, n))%>%
ggplot(aes(word, n, fill = sentiment)) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = c("red2", "green3")) +
facet_wrap(~sentiment, scales = "free_y") +
ylim(0, 120) +
labs(y = NULL, x = NULL) +
coord_flip() +
theme_minimal()Słownik nrc
Leksykon nrc kategoryzuje słowa w podziale na pozytywne, negatywne, gniew, wstręt, strach, radość, smutek, zaskoczenie i zaufania itd.
## # A tibble: 13,901 x 2
## word sentiment
## <chr> <chr>
## 1 abacus trust
## 2 abandon fear
## 3 abandon negative
## 4 abandon sadness
## 5 abandoned anger
## 6 abandoned fear
## 7 abandoned negative
## 8 abandoned sadness
## 9 abandonment anger
## 10 abandonment fear
## # ... with 13,891 more rows
wykres1 <- df %>%
inner_join(get_sentiments("nrc"), by = "word") %>%
filter(sentiment=="positive") %>%
ggplot(aes(word, n, fill = sentiment)) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = c("green3")) +
facet_wrap(~sentiment, scales = "free_y") +
ylim(0, 200) +
labs(y = NULL, x = NULL) +
coord_flip() +
theme_minimal()Pozostałe wykresy powstawały poprzez zamienienie wartości “sentiment”
Analiza “klastrowa”
corpustdm <- TermDocumentMatrix(Corpus, control = list(minWordLength=c(1,Inf)))
t <- removeSparseTerms(corpustdm,sparse=0.98)
m <- as.matrix(t)
distance <- dist(scale(m))
print(distance, digits = 2)## can just will make true now launch much one good yes tesla sure haha
## just 70
## will 106 113
## make 57 68 104
## true 66 76 110 64
## now 62 72 106 59 67
## launch 64 74 106 62 70 62
## much 71 80 112 68 76 72 75
## one 61 71 106 57 67 62 65 71
## good 67 77 110 64 72 67 70 76 66
## yes 82 90 119 80 86 82 85 90 83 87
## tesla 91 98 124 90 96 92 95 99 93 96 107
## sure 64 74 108 60 70 65 68 74 64 70 84 94
## haha 61 72 107 58 61 62 64 72 61 66 82 93 64
## great 72 80 114 69 76 72 75 81 72 77 90 99 75 72
## yeah 63 72 107 60 68 63 66 73 62 68 83 93 66 63
## great
## just
## will
## make
## true
## now
## launch
## much
## one
## good
## yes
## tesla
## sure
## haha
## great
## yeah 72
op = par(bg = "#DDE3CA")
plot(hc, col = "#487AA1", col.main = "#45ADA8", col.lab = "#7C8071",
col.axis = "#F38630", lwd = 3, lty = 3, sub = "", hang = -1, axes = FALSE)
axis(side = 2, at = seq(0, 400, 100), col = "#F38630", labels = FALSE,
lwd = 2)
mtext(seq(0, 400, 100), side = 2, at = seq(0, 400, 100), line = 1,
col = "#A38630", las = 2)mypal = c("#556270", "#4ECDC4", "#1B676B", "#FF6B6B", "#C44D58")
clus5 = cutree(hc, 5)
op = par(bg = "#E8DDCB")
plot(as.phylo(hc), type = "fan", tip.color = mypal[clus5], label.offset = 1,
cex = log(mtcars$mpg, 10), col = "red")hc1 <- hclust(distance, method = "complete")
hc2 <- hclust(distance, method = "ward.D2")
dendrogram1 <- as.dendrogram (hc1)
dendrogram2 <- as.dendrogram (hc2)
tanglegram(dendrogram1, dendrogram2)Podsumowanie
Środowisko R oprócz danych liczbowych pozwala również na wykonanie dokładnych analiz tekstowych bądź pojedynczych słów. Pozwala na odkrywanie statystycznych zależności oraz schematów. W pracy przedstawiono tylko jedne z wielu sposobów na przetworzenie tego rodzaju danych. Jest ich zdecydowanie więcej z czego ochoczo korzystają wszelakiego rodzaju przedsiębiorstwa oraz instytucje.