데이터 과학

트럼프 트윗

학습 목표

  • 트럼프 트위터 트윗을 통해 지금까지 학습 내용을 적용한다.

1. 트럼프 트위터 트윗 1 2

broom 팩키지 저자로 유명한 David Robinson의 트럼프 트위터 분석을 통해 지금까지 학습한 사항을 실무에 적용해 본다.

트럼프 트윗 중에서 특정 단어가 들어간 트윗에서 단어를 추출하는 것이다.

즉, regex <- "badly|crazy|weak|spent|strong|dumb|joke|guns|funny|dead" 정규표현식에 패턴으로 단어를 등록해 넣고 이를 트윗에서 추출한다.

트럼프 트윗 단어 추출

2. 함수형 프로그래밍을 활용하여 트윗 단어 추출

2.1. 환경 설정

함수형 프로그래밍 purrr, 데이터 조작 dplyr, 데이터프레임 tibble 팩키지를 불러온다.

# 0. 환경설정 ----------------------------------------------------
library(purrr)
library(dplyr)
library(tibble)

2.2. 트럼프 트윗 데이터 가져오기

웹사이트에 공개된 http://varianceexplained.org/files/trump_tweets_df.rda 트럼프 트윗 데이터를 불러와서 일별한다. strtrim() 함수는 인자로 넣은 70 글자수에 맞춰 트윗을 끊어주는 역할을 한다.

# 1. 데이터 가져오기 ----------------------------------------------------

load(url("http://varianceexplained.org/files/trump_tweets_df.rda"))
# load("trump_tweets_df.rda")
glimpse(trump_tweets_df)
#> Observations: 1,512
#> Variables: 16
#> $ text          <chr> "My economic policy speech will be carried live ...
#> $ favorited     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,...
#> $ favoriteCount <dbl> 9214, 6981, 15724, 19837, 34051, 29831, 19223, 1...
#> $ replyToSN     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
#> $ created       <dttm> 2016-08-08 15:20:44, 2016-08-08 13:28:20, 2016-...
#> $ truncated     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,...
#> $ replyToSID    <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
#> $ id            <chr> "762669882571980801", "762641595439190016", "762...
#> $ replyToUID    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
#> $ statusSource  <chr> "<a href=\"http://twitter.com/download/android\"...
#> $ screenName    <chr> "realDonaldTrump", "realDonaldTrump", "realDonal...
#> $ retweetCount  <dbl> 3107, 2390, 6691, 6402, 11717, 9892, 5784, 7930,...
#> $ isRetweet     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,...
#> $ retweeted     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,...
#> $ longitude     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
#> $ latitude      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...

tweets <- trump_tweets_df$text
tweets %>% head() %>% strtrim(70)
#> [1] "My economic policy speech will be carried live at 12:15 P.M. Enjoy!"   
#> [2] "Join me in Fayetteville, North Carolina tomorrow evening at 6pm. Ticke"
#> [3] "#ICYMI: \"Will Media Apologize to Trump?\" https://t.co/ia7rKBmioA"    
#> [4] "Michael Morell, the lightweight former Acting Director of C.I.A., and "
#> [5] "The media is going crazy. They totally distort so many things on purpo"
#> [6] "I see where Mayor Stephanie Rawlings-Blake of Baltimore is pushing Cro"

2.3. 트럼프 트윗 데이터 표본 추출 : 트윗 7개만

트럼프 트윗 전체를 분석하기 전에 특정 트윗 일부, 7개만 추출한다.

# 2. 트럼프 안드로이드 단어 ----------------------------------------------------
regex <- "badly|crazy|weak|spent|strong|dumb|joke|guns|funny|dead"

tweets <- tweets[c(1, 2, 5, 6, 198, 347, 919)]
tweets %>% strtrim(70)
#> [1] "My economic policy speech will be carried live at 12:15 P.M. Enjoy!"   
#> [2] "Join me in Fayetteville, North Carolina tomorrow evening at 6pm. Ticke"
#> [3] "The media is going crazy. They totally distort so many things on purpo"
#> [4] "I see where Mayor Stephanie Rawlings-Blake of Baltimore is pushing Cro"
#> [5] "Bernie Sanders started off strong, but with the selection of Kaine for"
#> [6] "Crooked Hillary Clinton is unfit to serve as President of the U.S. Her"
#> [7] "The Cruz-Kasich pact is under great strain. This joke of a deal is fal"

2.4. 정규표현식을 활용한 단어 추출

regmatches 함수를 사용하면 트럼프 트윗에서 단어를 추출할 수 있다.

# 3. gregexpr() 정규표현식 사용 ----------------------------------------------------
regmatches(tweets, gregexpr(regex, tweets)) 
#> [[1]]
#> character(0)
#> 
#> [[2]]
#> character(0)
#> 
#> [[3]]
#> [1] "crazy"
#> 
#> [[4]]
#> [1] "joke"
#> 
#> [[5]]
#> [1] "strong" "weak"  
#> 
#> [[6]]
#> [1] "weak"   "strong"
#> 
#> [[7]]
#> [1] "joke" "dead" "dumb"

2.5. 함수형 프로그래밍을 활용한 트윗 단어 추출

pmap 함수에 인자로 넘기기 위해서 사전에 준비작업을 수행하고 나서, pmap 함수에 넣어 트럼프 트윗에서 매칭되는 단어를 추출한다.

# 4. substring() 함수 미리 살펴보기 ------------------------------------------------
matches <- gregexpr(regex, tweets)

(match_first <- map(matches, as.vector))
#> [[1]]
#> [1] -1
#> 
#> [[2]]
#> [1] -1
#> 
#> [[3]]
#> [1] 20
#> 
#> [[4]]
#> [1] 134
#> 
#> [[5]]
#> [1] 28 95
#> 
#> [[6]]
#> [1]  87 114
#> 
#> [[7]]
#> [1]  50 112 123
(match_length <- map(matches, attr, which = "match.length"))
#> [[1]]
#> [1] -1
#> 
#> [[2]]
#> [1] -1
#> 
#> [[3]]
#> [1] 5
#> 
#> [[4]]
#> [1] 4
#> 
#> [[5]]
#> [1] 6 4
#> 
#> [[6]]
#> [1] 4 6
#> 
#> [[7]]
#> [1] 4 4 4
(match_last <- map2(match_first, match_length, ~ .x + .y - 1))
#> [[1]]
#> [1] -3
#> 
#> [[2]]
#> [1] -3
#> 
#> [[3]]
#> [1] 24
#> 
#> [[4]]
#> [1] 137
#> 
#> [[5]]
#> [1] 33 98
#> 
#> [[6]]
#> [1]  90 119
#> 
#> [[7]]
#> [1]  53 115 126

tibble(
    naive_length = lengths(matches),
    n_words = map_int(matches, ~ sum(.x > 0))
)
#> # A tibble: 7 × 2
#>   naive_length n_words
#>          <int>   <int>
#> 1            1       0
#> 2            1       0
#> 3            1       1
#> 4            1       1
#> 5            2       2
#> 6            2       2
#> 7            3       3

pmap(list(text = tweets, first = match_first, last = match_last), substring)
#> [[1]]
#> [1] ""
#> 
#> [[2]]
#> [1] ""
#> 
#> [[3]]
#> [1] "crazy"
#> 
#> [[4]]
#> [1] "joke"
#> 
#> [[5]]
#> [1] "strong" "weak"  
#> 
#> [[6]]
#> [1] "weak"   "strong"
#> 
#> [[7]]
#> [1] "joke" "dead" "dumb"

mdf <- tibble(
    text = tweets,
    first = match_first,
    last = match_last
)
pmap(mdf, substring)
#> [[1]]
#> [1] ""
#> 
#> [[2]]
#> [1] ""
#> 
#> [[3]]
#> [1] "crazy"
#> 
#> [[4]]
#> [1] "joke"
#> 
#> [[5]]
#> [1] "strong" "weak"  
#> 
#> [[6]]
#> [1] "weak"   "strong"
#> 
#> [[7]]
#> [1] "joke" "dead" "dumb"

3. 매칭 리스트를 불러오는 세가지 방법

매칭 리스트를 불러오는 방법은 세가지가 존재한다.

  • 사용자 정의 함수를 사전에 정의하고 호출
  • 무명함수 사용
  • 내장함수를 활용하는데 인자를 넘기는 방법
# 5.1. 함수 정의 후 호출
ml <- function(x) attr(x, which = "match.length")
map(matches, ml)
#> [[1]]
#> [1] -1
#> 
#> [[2]]
#> [1] -1
#> 
#> [[3]]
#> [1] 5
#> 
#> [[4]]
#> [1] 4
#> 
#> [[5]]
#> [1] 6 4
#> 
#> [[6]]
#> [1] 4 6
#> 
#> [[7]]
#> [1] 4 4 4
# 5.2. 무명함수 
(map(matches, ~ attr(.x, which = "match.length")))
#> [[1]]
#> [1] -1
#> 
#> [[2]]
#> [1] -1
#> 
#> [[3]]
#> [1] 5
#> 
#> [[4]]
#> [1] 4
#> 
#> [[5]]
#> [1] 6 4
#> 
#> [[6]]
#> [1] 4 6
#> 
#> [[7]]
#> [1] 4 4 4
# 5.3. 내장함수 활용 후 인자 넘기는 방법
(match_length <- map(matches, attr, which = "match.length"))
#> [[1]]
#> [1] -1
#> 
#> [[2]]
#> [1] -1
#> 
#> [[3]]
#> [1] 5
#> 
#> [[4]]
#> [1] 4
#> 
#> [[5]]
#> [1] 6 4
#> 
#> [[6]]
#> [1] 4 6
#> 
#> [[7]]
#> [1] 4 4 4