“트윗(tweet)”이란 말은 작은 새가 지저귀는 소리를 나타내는 영어 낱말로, 트위터(영어: Twitter)는 소셜 네트워크 서비스(SNS)이자 마이크로블로그 서비스로 볼 수 있다.
단문 메시지 서비스(SMS), 인스턴트 메신저, 전자 우편(e-mail) 등을 통해 “트윗(tweet)”를 전송할 수 있고, 글 한 편에 해당하는 단위는 트윗으로 140자가 한도가 된다. 한글이든 영문이든, 공백과 기호를 포함해 한 번에 140 까지 글자를 올릴 수 있다. 최근 Donald J. Trump 대통령이 트워터를 적극적으로 정치에 활용하면서 다시 관심을 받고 있는 서비스이기도 하다.
월기준으로 3.3억 사용자가 있으며, 매일 5억개의 트윗이 있고, 사용자의 80%가 축복받은 1980~2000년 초반 출생한 밀레니얼 세대이며, 생중계 동안 트위터 광고는 11% 더 효과적으로 알려져 있으며 구매자의 40%는 트위터의 영향을 받는 것으로 조사된다.
rtweet
팩키지 stream_tweets()
함수는 공개가 허락된 트윗 중에서 1%를 무작위로 가져오는데 기본설정으로 30초 동안 트윗을 추출한다.
트위터 데이터를 분석해서 다양한 분야에 활용할 수 있다. 대표적으로 다음을 들 수 있다.
rtweet
httpuv
: HTTP and WebSocket server package for R를 기반한 rtweet
: R client for accessing Twitter’s REST and stream APIs 팩키지로 천하통일 되었다고 볼 수 있다.
httpuv
: 웹브라우저를 통해 트위터 API를 인증할 수 있게 함. 따라서, 별도 트위터 개발자 페이지에 접속해서 인증키를 받아 이를 활용할 필요가 없어짐.rtweet
: 트위터 API에서 데이터를 추출해서 분석이 가능한 형태의 데이터프레임으로 가공하여 반환시킴설치는 install.packages("rtweet")
으로 하면 쉽게 설치되고 별도 인증절차 없이 처음 브라우저 인증을 위한 과정만 추가된다. 이후 search_tweets()
등 함수를 사용해서 트위터 API에서 데이터를 수집하면 된다.
# 0. 환경설정 -----
library(rtweet) # install.packages("rtweet")
library(tidyverse)
tidyverse_tw <- search_tweets("#tidyverse", n = 100, include_rts = TRUE, lang = "en")
tidyverse_tw
# A tibble: 100 x 90
user_id status_id created_at screen_name text source
<chr> <chr> <dttm> <chr> <chr> <chr>
1 176548… 12118861… 2019-12-31 05:45:48 ohebie "I m… Twitt…
2 101181… 12118436… 2019-12-31 02:57:00 rstatstweet "I m… rstat…
3 101181… 12104558… 2019-12-27 07:02:21 rstatstweet geom… rstat…
4 101181… 12104446… 2019-12-27 06:17:39 rstatstweet Usin… rstat…
5 101181… 12105724… 2019-12-27 14:45:46 rstatstweet Chan… rstat…
6 101181… 12105724… 2019-12-27 14:45:46 rstatstweet R- m… rstat…
7 101181… 12105724… 2019-12-27 14:45:45 rstatstweet Noth… rstat…
8 101181… 12106026… 2019-12-27 16:45:29 rstatstweet Comp… rstat…
9 101181… 12116549… 2019-12-30 14:26:56 rstatstweet What… rstat…
10 101181… 12107115… 2019-12-27 23:58:28 rstatstweet Hey … rstat…
# … with 90 more rows, and 84 more variables: display_text_width <dbl>,
# reply_to_status_id <chr>, reply_to_user_id <chr>,
# reply_to_screen_name <chr>, is_quote <lgl>, is_retweet <lgl>,
# favorite_count <int>, retweet_count <int>, quote_count <int>,
# reply_count <int>, hashtags <list>, symbols <list>, urls_url <list>,
# urls_t.co <list>, urls_expanded_url <list>, media_url <list>,
# media_t.co <list>, media_expanded_url <list>, media_type <list>,
# ext_media_url <list>, ext_media_t.co <list>,
# ext_media_expanded_url <list>, ext_media_type <chr>,
# mentions_user_id <list>, mentions_screen_name <list>, lang <chr>,
# quoted_status_id <chr>, quoted_text <chr>, quoted_created_at <dttm>,
# quoted_source <chr>, quoted_favorite_count <int>,
# quoted_retweet_count <int>, quoted_user_id <chr>,
# quoted_screen_name <chr>, quoted_name <chr>,
# quoted_followers_count <int>, quoted_friends_count <int>,
# quoted_statuses_count <int>, quoted_location <chr>,
# quoted_description <chr>, quoted_verified <lgl>,
# retweet_status_id <chr>, retweet_text <chr>,
# retweet_created_at <dttm>, retweet_source <chr>,
# retweet_favorite_count <int>, retweet_retweet_count <int>,
# retweet_user_id <chr>, retweet_screen_name <chr>, retweet_name <chr>,
# retweet_followers_count <int>, retweet_friends_count <int>,
# retweet_statuses_count <int>, retweet_location <chr>,
# retweet_description <chr>, retweet_verified <lgl>, place_url <chr>,
# place_name <chr>, place_full_name <chr>, place_type <chr>,
# country <chr>, country_code <chr>, geo_coords <list>,
# coords_coords <list>, bbox_coords <list>, status_url <chr>,
# name <chr>, location <chr>, description <chr>, url <chr>,
# protected <lgl>, followers_count <int>, friends_count <int>,
# listed_count <int>, statuses_count <int>, favourites_count <int>,
# account_created_at <dttm>, verified <lgl>, profile_url <chr>,
# profile_expanded_url <chr>, account_lang <lgl>,
# profile_banner_url <chr>, profile_background_url <chr>,
# profile_image_url <chr>
트위터 헬로월드를 찍게 되면 get_trends()
함수로 아무 생각없을 때 세상에 어떤 일이 일어나고 있는지 알아볼 수 있다. 어떤 주제가 뜨고 있고 어느 지역에서 그런 일이 일어나는지 파악하는데 도움이 된다. search_tweets()
는 특정 해쉬태그 등 검색어를 넣어 관심 트윗을 얻어내는데 사용한다. lookup_users()
는 트위터 계정에 대한 정보를 얻는데 도움을 얻을 수 있다.
트윗 검색 함수에 검색어를 넣게 되면 모든 트윗을 다 가져온다. 마치 SQL 문의 SELECT * FROM ...
와 같은 것이라 때로는 불필요한 정보가 포함되어 추후 다시 데이터 정제작업을 수행할 때가 있다. 이를 보완하고자 다양한 검색 옵션을 rtweet
팩키지에서 제공한다. 물론 트위터 API에서 따온 것이기는 하다.
먼저 활동성 통계량을 특정하여 트윗검색하는 방법을 살펴보자. search_tweets()
함수 내부에 검색어와 min_faves
, min_retweets
를 넣는다. lang='en'
으로 언어도 영어로 한정한다.
#CloudComputing
min_faves:10
AND
min_retweets:10
lang='en'
cloud_option_twts <- search_tweets("#CloudComputing min_faves:10 AND min_retweets:10", lang='en')
cloud_option_twts %>%
select(screen_name, favorite_count, retweet_count, text) %>%
arrange(desc(favorite_count)) %>%
DT::datatable()
이외에도 retweets
, quote
, replies
를 제거한 트윗을 얻기 위해 filter:
선택옵션을 추가한다.
가장 먼저 특정 지역에 가장 유행하는 주제가 무엇인지 찾아보자. 이를 트위터 트렌드(twitter trend)라고 흔히 부른다. get_trends()
함수를 사용하게 되면 전세계 트윗을 해쉬태그(hashtag), 키워드, 이벤트, 지역 등을 분석해서 최신 유행하는 주제를 파악할 수 있다.
trends_available()
함수를 사용하게 되면 추출가능한 트렌드에 대한 정보를 얻을 수 있는데 countryCode
를 한국(“KR”)으로 특정해서 대한민국과 연관된 트렌드만 파악할 수 있도록 한다.
# A tibble: 15 x 8
name url parentid country woeid countryCode code place_type
<chr> <chr> <int> <chr> <int> <chr> <int> <chr>
1 Goyang http://wher… 23424868 Korea 1.13e6 KR 7 Town
2 Yongin http://wher… 23424868 Korea 1.13e6 KR 7 Town
3 Ansan http://wher… 23424868 Korea 1.13e6 KR 7 Town
4 Buche… http://wher… 23424868 Korea 1.13e6 KR 7 Town
5 Busan http://wher… 23424868 Korea 1.13e6 KR 7 Town
6 Chang… http://wher… 23424868 Korea 1.13e6 KR 7 Town
7 Daegu http://wher… 23424868 Korea 1.13e6 KR 7 Town
8 Gwang… http://wher… 23424868 Korea 1.13e6 KR 7 Town
9 Inche… http://wher… 23424868 Korea 1.13e6 KR 7 Town
10 Seong… http://wher… 23424868 Korea 1.13e6 KR 7 Town
11 Suwon http://wher… 23424868 Korea 1.13e6 KR 7 Town
12 Ulsan http://wher… 23424868 Korea 1.13e6 KR 7 Town
13 Seoul http://wher… 23424868 Korea 1.13e6 KR 7 Town
14 Daeje… http://wher… 23424868 Korea 2.35e6 KR 7 Town
15 Korea http://wher… 1 Korea 2.34e7 KR 12 Country
2019-12-28 오후 10시 “#SBS는_책임져라” 해쉬태그가 가장 유행하는 주제로 나온다.
library(glue)
korea_woeid <- availabel_trends %>%
filter(countryCode == "KR", woeid == 23424868) %>%
select(woeid) %>%
pull(woeid)
korea_trend <- get_trends(korea_woeid)
korea_trend %>%
group_by(trend) %>%
summarise(mean_tweet_volume = mean(tweet_volume, na.rm = TRUE)) %>%
arrange(desc(mean_tweet_volume))
# A tibble: 50 x 2
trend mean_tweet_volume
<chr> <dbl>
1 파트라 24213
2 #별명만들기 NaN
3 #카이_스포일러 NaN
4 강원기 NaN
5 곰표패딩 NaN
6 국민의 신뢰 NaN
7 국민의 정치적 선택 NaN
8 그란디스 NaN
9 너무나 옹색 NaN
10 뇌물수수 NaN
# … with 40 more rows
궁금해서 twitter에 검색을 해보니… 레드벨벳 웬디가 SBS ‘가요대전’ 추락사고가 발생되서 팬들이 SBS를 질타하는 내용임을 확인할 수 있다.
사고 발생 후 4일이 흘렀는데 아직도 이게 안됩니까?
— 린넨커튼&벨벳로프 (@dj_netrider) December 28, 2019
사고 경위, 사고 발생 원인과 책임 소재 규명, 총책임자의 사과, 구체적인 피해 보상계획, 사고 재발 방지를 위한 대책이 포함된 정식 사과문. #SBS는_책임져라#TakeResponsibilitySBS@SBSNOW#WaitingForWendy
클라우드 경쟁이 치열하다. 아마존 AWS를 비롯하여 마이크로소프트 Azure, Google Cloud, IBM 그리고 최근에는 알리바바가 폭풍성장을 하고 있다. CIODIVE, “AWS to encounter IaaS market ‘erosion’ as contenders mature” 기사 내용과 비교하여 한국에서 트윗되고 있는 내용과 비교해보자.
library(rvest)
cloud_url <- "https://www.ciodive.com/news/iaas-Azure-AWS-Google-Cloud-Alibaba/559716/"
cloud_df <- cloud_url %>%
read_html() %>%
html_nodes(xpath='//*[@id="main-content"]/article/div[2]/div[2]/div/div[1]/div[3]/table') %>%
html_table() %>%
.[[1]]
cloud_df %>%
select(-`Growth, 2017-2018`) %>%
pivot_longer(cols=contains("Market")) %>%
mutate(value = parse_number(value) / 100) %>%
mutate(name = str_replace(name, "Market share, ", "MS_")) %>%
mutate(Company = factor(Company, levels = c("Amazon", "Microsoft Azure", "Alibaba", "Google Cloud","IBM", "Others"))) %>%
ggplot(aes(x=name, y=value, fill=name)) +
geom_col() +
# scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
scale_y_continuous(labels = scales::percent) +
facet_wrap(~Company) +
labs(x="", y="시장 점유율(%)") +
scale_fill_manual(values=c("darkgray", "blue")) +
theme_bw() +
theme(legend.position = "none")
lang="ko"
로 클라우드 3사를 비교하는 것은 트윗이 너무 적어서 포기함.
aws_tw <- search_tweets("#AWS", n = 18000, include_rts = FALSE, lang="ko")
azure_tw <- search_tweets("#Azure", n = 18000, include_rts = FALSE, lang="ko")
gcp_tw <- search_tweets("#GCP", n = 18000, include_rts = FALSE, lang="ko")
alibaba_tw <- search_tweets("#AlibabaCloud", n = 18000, include_rts = FALSE, lang="ko")
n = 18000
을 두는 이유는 최대 트윗 갯수가 18,000이라 최대한 트윗을 땡겨온다. Rate limit exceeded - 88 이슈가 있어 1,800으로 트윗 갯수를 줄여서 작업한다. 현재 시점 2019-12-31 최근 1주일정도 추세를 보는데 큰 무리는 없어 보인다.
aws_tw <- search_tweets("#AWS", n = 1800, include_rts = FALSE)
azure_tw <- search_tweets("#Azure", n = 1800, include_rts = FALSE)
gcp_tw <- search_tweets("#googlecloud", n = 1800, include_rts = FALSE)
alibaba_tw <- search_tweets("#AlibabaCloud", n = 1800, include_rts = FALSE)
aws_ts_df <- ts_data(aws_tw, by="hours")
azure_ts_tw <- ts_data(azure_tw, by="hours")
gcp_ts_tw <- ts_data(gcp_tw, by="hours")
alibaba_ts_tw <- ts_data(alibaba_tw, by="hours")
aws_ts_df %>%
rename(aws=n) %>%
left_join(azure_ts_tw, by="time") %>%
rename(azure=n) %>%
left_join(gcp_ts_tw, by="time") %>%
rename(google=n) %>%
left_join(alibaba_ts_tw, by="time") %>%
rename(alibaba=n) %>%
pivot_longer(-time) %>%
ggplot(aes(x=time, y=value, color=name, group=name)) +
geom_line() +
geom_point() +
labs(x="", y="트윗횟수", color="클라우드 서비스") +
theme_bw() +
theme(legend.position = "top")
#CloudComputing
#CloudComputing
을 가장 많이 언급하는 트윗 사용자를 찾아보자. 이를 위해서 먼저 search_tweets()
함수로 해쉬태그 “#CloudComputing”을 넣고 screen_name
을 기준으로 트윗횟수를 세어본다.
cloud_twts <- search_tweets("#CloudComputing", n=1800)
cloud_twts %>%
count(screen_name, name="트윗수", sort=TRUE)
# A tibble: 815 x 2
screen_name 트윗수
<chr> <int>
1 LlnuxBot 69
2 IAM__Network 65
3 byte_code_ 53
4 ServerlessFan 32
5 chidambara09 29
6 rstatstweet 25
7 cybersec_feeds 23
8 reversepython 23
9 DeepSingularity 20
10 gp_pulipaka 20
# … with 805 more rows
#CloudComputing
해쉬태그 상위 10명을 추출하여 lookup_users()
함수로 활동성과 관련된 지표를 추출한다.
top_users <- cloud_twts %>%
count(screen_name, name="트윗수", sort=TRUE) %>%
top_n(10, wt=트윗수) %>%
pull(screen_name)
lookup_users(top_users) %>%
# select(screen_name, contains("_count")) %>%
select(screen_name, statuses_count, followers_count, friends_count, favourites_count)
# A tibble: 11 x 5
screen_name statuses_count followers_count friends_count
<chr> <int> <int> <int>
1 LlnuxBot 63124 584 1
2 IAM__Netwo… 500184 16198 13156
3 byte_code_ 16453 315 21
4 Serverless… 181780 2586 6
5 chidambara… 842320 5889 13
6 rstatstweet 127973 4966 25
7 cybersec_f… 497065 5364 0
8 reversepyt… 10281 276 16
9 DeepSingul… 39179 4885 4
10 gp_pulipaka 51829 73664 27663
11 RaymondWSA… 15353 81 2
# … with 1 more variable: favourites_count <int>
트윗 유저 상기 활동성 지표를 ggplot
으로 시각화하여 각 사용자별 특성을 직관적으로 파악할 수 있도록 한다.
lookup_users(top_users) %>%
select(screen_name, statuses_count, followers_count, friends_count, favourites_count) %>%
pivot_longer(-screen_name) %>%
ggplot(aes(x=screen_name, y=value, fill=screen_name)) +
geom_col() +
coord_flip() +
scale_y_continuous(labels=scales::comma) +
facet_wrap(~name, scales = "free") +
labs(x="", y="") +
theme_bw() +
theme(legend.position = "none")
#CloudComputing
관련 트윗 검색어를 넣어 include_rts = TRUE
리트윗을 추적해보자. 이를 위해서 먼저 screen_name
, retweet_screen_name
을 넣어 엣지리스트 데이터프레임을 만든다. 그리고 나서, graph_from_data_frame()
함수로 데이터프레임을 네트워크 자료형으로 변환시킨다.
library(igraph)
cc_twts <- search_tweets("#CloudComputing ", n=100, include_rts = TRUE)
cc_twts_edgelist <- cc_twts %>%
select(screen_name, retweet_screen_name, followers_count) %>%
filter(complete.cases(.))
cc_twts_nw <- graph_from_data_frame(cc_twts_edgelist, directed = TRUE)
plot(cc_twts_nw,
asp = 9/16,
vertex.size = 5,
vertex.color = "skyblue",
edge.arrow.size = 0.1,
edge.color = "darkgray",
vertex.label.cex = 0.7,
vertex.label.color = "black")
네트워크 분석의 중요한 내용으로 중심성(centrality) 등 기술통계량을 추출하여 고급 분석을 이어간다. 이에 대한 자세한 사항은 데이터 과학 – 네트워크를 참조한다.
#volcano
관련 트윗 검색어를 어디에서 많이 하는지 공간정보가 포함되어 있는 경우 이를 반영시킨다. lat_lng()
함수를 사용하면 “coords_coords”, “bbox_coords”, “geo_coords” 칼럼을 참고해서 위경도 정보를 추출한다. 이를 leaflet
팩키지를 활용하여 공간정보 시각화를 한다.
library(leaflet)
# 트윗 가져오기
geo_twts <- search_tweets("#volcano ", n=1000, include_rts = TRUE)
geo_twts_df <- lat_lng(geo_twts) %>%
select(screen_name, text, lng, lat) %>%
filter(!is.na(lng))
geo_twts_df %>%
leaflet() %>%
addProviderTiles(providers$OpenStreetMap) %>%
addMarkers(lng=~lng, lat=~lat, clusterOptions = markerClusterOptions(),
popup = ~ as.character(paste0("<strong>", paste0("유저명: ",`screen_name`), "</strong><br>",
"-----------------------------------------------------------<br>",
"· 트윗: ", text)))
#CloudComputing
관련 트윗 검색어를 텍스트 데이터로 놓고 이를 자연어처리 분석을 추진한다. 이를 위해서 tidytext
팩키지를 통해 단어 토큰을 만들이고 불용어 처리한 후에 단어 빈도수를 시각화해 보자.
library(tidytext)
cc_twts <- search_tweets("#CloudComputing ", n=1000, include_rts = FALSE)
count_df <- cc_twts %>%
select(status_id, text) %>%
unnest_tokens(word, text) %>%
anti_join(stop_words, by = "word") %>%
count(word, sort = TRUE) %>%
top_n(15, wt=n)
count_df %>%
ggplot(aes(x=fct_reorder(word, n), y=n)) +
geom_col() +
coord_flip() +
labs(x="", y="") +
scale_y_continuous(labels = scales::comma) +
theme_bw()