class: title0 Do it! 쉽게 배우는 R 텍스트 마이닝 --- class: no-page-num <br> .pull-left[ <img src="https://raw.githubusercontent.com/youngwoos/Doit_textmining/main/cover.png" width="70%" height="70%" /> ] .pull-right[ <br> <br> <br> <svg viewBox="0 0 496 512" xmlns="http://www.w3.org/2000/svg" style="height:1em;fill:currentColor;position:relative;display:inline-block;top:.1em;"> [ comment ] <path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path></svg> [github.com/youngwoos/Doit_textmining](https://github.com/youngwoos/Doit_textmining) <svg viewBox="0 0 448 512" xmlns="http://www.w3.org/2000/svg" style="height:1em;fill:currentColor;position:relative;display:inline-block;top:.1em;"> [ comment ] <path d="M400 32H48A48 48 0 0 0 0 80v352a48 48 0 0 0 48 48h137.25V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.27c-30.81 0-40.42 19.12-40.42 38.73V256h68.78l-11 71.69h-57.78V480H400a48 48 0 0 0 48-48V80a48 48 0 0 0-48-48z"></path></svg> [facebook.com/groups/datacommunity](https://facebook.com/groups/datacommunity) - [네이버책](https://book.naver.com/bookdb/book_detail.nhn?bid=17891971) - [yes24](http://bit.ly/3oUuJOB) - [알라딘](http://bit.ly/3oXOSDn) - [교보문고](https://bit.ly/2LtNOcB) ] --- class: title0 08 텍스트 마이닝 프로젝트: 차기 대선 주자 SNS 여론 분석 --- class: title0-2 We'll make <br-back-30> <img src="Image/08/08_1_5.png" width="53%" /> --- class: title0-2 We'll make <br-back-30> <img src="Image/08/08_3_2.png" width="43%" /> --- class: title0-2 We'll make <br-back-30> <img src="Image/08/08_4_5.png" width="50%" /> --- class: title0-2 and <br-back-40> <img src="Image/08/08_6_4.png" width="50%" /> --- <br> .large2[.font-jua[목차]] .large[.font-jua[08-1 SNS 언급량 추이 살펴보기]]([link](#08-1)) .large[.font-jua[08-2 SNS 이슈 알아보기]]([link](#08-2)) .large[.font-jua[08-3 감정 단어 살펴보기]]([link](#08-3)) .large[.font-jua[08-4 감정 경향 살펴보기]]([link](#08-4)) .large[.font-jua[08-5 감정 추이 살펴보기]]([link](#08-5)) .large[.font-jua[08-6 긍정, 부정 트윗 단어 비교하기]]([link](#08-6)) --- name: 08-1 class: title1 08-1 SNS 언급량 추이 살펴보기 --- ##### SNS 데이터를 분석해서 사람들이 대통령 후보를 어떻게 생각하는지 알아보기 - 20대 대통령 선거 유력 후보: 이낙연 의원, 이재명 경기도지사 ##### 분석 절차 - 1.트윗 작성 날짜 및 후보자별 언급 빈도를 구합니다. - 2.선 그래프와 영역 차트를 만들어 추이를 살펴봅니다. --- #### 기본적인 전처리 - 이낙연 의원, 이재명 경기도지사를 언급한 트위터 데이터(2020년 8월 13일~21일) - 두 후보를 함께 언급한 트윗 있으므로 `bind_tweet`에는 중복된 행이 포함됨 ```r # 데이터 불러오기 library(dplyr) library(readr) bind_tweet <- bind_rows( read_csv("tweet_nak.csv") %>% mutate(candidate = "이낙연"), read_csv("tweet_jae.csv") %>% mutate(candidate = "이재명")) glimpse(bind_tweet) ``` ``` ## Rows: 13,928 ## Columns: 5 ## $ status_id <dbl> 1.296742e+18, 1.296737e+18, 1.296354e+18, 1.2... ## $ screen_name <chr> "iloveabc0712", "park_pyung", "park_pyung", "... ## $ created_at <dttm> 2020-08-21 09:33:09, 2020-08-21 09:13:52, 20... ## $ text <chr> "@nylee21 @nylee_office 29일 전당대회 기다리고 있습니다. 이... ## $ candidate <chr> "이낙연", "이낙연", "이낙연", "이낙연", "이낙연", "이낙연", "이낙... ``` --- ##### 전처리 절차 <br10> - **사용자 아이디 태그 제거** - 트윗에는 사용자 아이디를 언급한 아이디 태그(@)가 있음 - `textclean::replace_tag()`를 이용해 아이디 태그 제거 - `stringr::str_to_lower()`를 이용해 소문자로 변환한 다음 적용 - **html 태그 제거** - 트윗에는 html 특수 문자가 포함되어 있어 출력하면 내용 알아보기 어려움 - `textclean::replace_html()`을 이용해 html 특수 문자 제거 - `stringr::str_squish()` 이용해 중복 공백 제거 - **날짜 변수 추가만들기** - `lubridate::date()`를 이용해 트윗 작성 시각에서 '년월일'을 추출한 변수 만들기 - 트윗을 날짜별로 분석할 때 활용 --- ##### 전처리 절차 <br10> - **광고 트윗 제거** - 트윗 광고에는 대부분 URL 링크가 있음 - `"https://"`가 포함된 텍스트 제거 - **중복 트윗 제거** - 한 사용자나 여러 사용자가 내용이 같은 트윗을 반복 게시하는 경우가 있음 - 내용이 같은 트윗은 후보별로 하나씩만 남기기 - **어뷰징 트윗 제거** - 트위터에는 극단적으로 트윗을 많이 올리는 사용자가 있음. - 이런 사용자가 작성한 트윗 모두 포함하면 분석 결과에 소수 의견 과도하게 반영되므로 제거하기 - `slice_sample()`을 이용해 사용자당 하루 최대 5개만 남기기 --- ```r install.packages("lubridate") library(lubridate) library(textclean) library(stringr) set.seed(1234) tweet <- bind_tweet %>% mutate(text = replace_tag(str_to_lower(text)), # id 태그 제거 text = str_squish(replace_html(text)), # html 특수 문자 제거 date = date(created_at)) %>% # 날짜 변수 생성 filter(!str_detect(text, "https://")) %>% # 광고 트윗 제거 group_by(candidate) %>% # 중복 글 제거 distinct(text, .keep_all = T) %>% group_by(candidate, date, screen_name) %>% # 사용자별 하루 최대 5개 추출 slice_sample(n = 5) %>% ungroup() glimpse(tweet) ``` --- ``` ## Rows: 8,337 ## Columns: 6 ## $ status_id <dbl> 1.293765e+18, 1.293839e+18, 1.29373... ## $ screen_name <chr> "0o0o0o0o0125", "1112_e_h", "1112_e... ## $ created_at <dttm> 2020-08-13 04:23:35, 2020-08-13 09... ## $ text <chr> "\"나 채식주의잔데 지금 치킨먹고싶다\" 한편 나라가 디비진다... ## $ candidate <chr> "이낙연", "이낙연", "이낙연", "이낙연", "이낙연", ... ## $ date <date> 2020-08-13, 2020-08-13, 2020-08-13... ``` --- #### 트윗 빈도 추이 ##### 1. 트윗 빈도 추이 선 그래프 - 날짜별로 어떤 후보를 언급한 트윗이 많은지 알아보기 .scroll-box-26[ ```r # 날짜, 후보별 빈도 frequency_date <- tweet %>% count(date, candidate) frequency_date ``` ``` ## # A tibble: 18 x 3 ## date candidate n ## <date> <chr> <int> ## 1 2020-08-13 이낙연 247 ## 2 2020-08-13 이재명 639 ## 3 2020-08-14 이낙연 709 ## 4 2020-08-14 이재명 1179 ## 5 2020-08-15 이낙연 153 ## 6 2020-08-15 이재명 462 ## 7 2020-08-16 이낙연 242 ## 8 2020-08-16 이재명 515 ## 9 2020-08-17 이낙연 295 ## 10 2020-08-17 이재명 454 ## 11 2020-08-18 이낙연 582 ## 12 2020-08-18 이재명 452 ## 13 2020-08-19 이낙연 628 ## 14 2020-08-19 이재명 338 ## 15 2020-08-20 이낙연 250 ## 16 2020-08-20 이재명 526 ## 17 2020-08-21 이낙연 143 ## 18 2020-08-21 이재명 523 ``` ] --- ```r # 선 그래프 library(ggplot2) ggplot(frequency_date, aes(x = date, y = n, col = candidate)) + geom_line() ``` <img src="08-project2_files/figure-html/unnamed-chunk-12-1.png" width="80%" /> --- ##### 그래프 다듬기 ```r col_candidate <- c("#619CFF", "#B79F00") # 후보 색상 목록 생성 ``` <br-back-10> ```r ggplot(frequency_date, aes(x = date, y = n, col = candidate)) + geom_line(size = 1) + geom_point(size = 2) + scale_x_date(date_labels = "%m/%d", # x축 날짜 포맷 date_breaks = "1 day") + # x축 날짜 간격 scale_y_continuous(limits = c(0, 1200), # y축 범위 breaks = seq(0, 1200, 300)) + # y축 간격 scale_color_manual(values = col_candidate) + # 선 색깔 labs(title = "차기 대선주자 트위터 언급량 추이", # 그래프 제목 subtitle = "2020.8.13 ~ 2020.8.21", # 보조 제목 x = NULL, y = NULL, col = NULL) + # 축 이름 삭제 theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), # 제목 폰트 plot.subtitle = element_text(size = 12), # 부제목 폰트 panel.grid.minor.x = element_blank()) # x축 보조축 삭제 ``` --- <svg viewBox="0 0 352 512" xmlns="http://www.w3.org/2000/svg" style="height:1em;fill:currentColor;position:relative;display:inline-block;top:.1em;"> [ comment ] <path d="M176 80c-52.94 0-96 43.06-96 96 0 8.84 7.16 16 16 16s16-7.16 16-16c0-35.3 28.72-64 64-64 8.84 0 16-7.16 16-16s-7.16-16-16-16zM96.06 459.17c0 3.15.93 6.22 2.68 8.84l24.51 36.84c2.97 4.46 7.97 7.14 13.32 7.14h78.85c5.36 0 10.36-2.68 13.32-7.14l24.51-36.84c1.74-2.62 2.67-5.7 2.68-8.84l.05-43.18H96.02l.04 43.18zM176 0C73.72 0 0 82.97 0 176c0 44.37 16.45 84.85 43.56 115.78 16.64 18.99 42.74 58.8 52.42 92.16v.06h48v-.12c-.01-4.77-.72-9.51-2.15-14.07-5.59-17.81-22.82-64.77-62.17-109.67-20.54-23.43-31.52-53.15-31.61-84.14-.2-73.64 59.67-128 127.95-128 70.58 0 128 57.42 128 128 0 30.97-11.24 60.85-31.65 84.14-39.11 44.61-56.42 91.47-62.1 109.46a47.507 47.507 0 0 0-2.22 14.3v.1h48v-.05c9.68-33.37 35.78-73.18 52.42-92.16C335.55 260.85 352 220.37 352 176 352 78.8 273.2 0 176 0z"></path></svg> `theme_minimal(12)`: `theme_`로 시작하는 `ggplot2` 테마 함수에 숫자를 입력하면 그래프의 전체 폰트 <br> 크기를 조정함 --- <br><br> <img src="08-project2_files/figure-html/unnamed-chunk-14-1.png" width="80%" style="display: block; margin: auto;" /> --- ##### 2. 트윗 빈도 추이 영역 차트 - `geom_area()`: 언급량 차이를 차이를 잘 표현하는 영역 차트(area chart) 만들기 - `position = "dodge"`: 두 후보의 영역 충첩 - `alpha = 0.6`: 투명하게 표현 ```r # 영역 그래프 ggplot(frequency_date, aes(x = date, y = n, fill = candidate)) + geom_area(position = "dodge", alpha = 0.6) ``` <img src="08-project2_files/figure-html/unnamed-chunk-15-1.png" width="58%" /> --- ##### 그래프 다듬기 ```r ggplot(frequency_date, aes(x = date, y = n, fill = candidate)) + geom_area(position = "dodge", alpha = 0.6) + geom_line(size = 0.5, alpha = 0.5) + scale_x_date(date_labels = "%m/%d", date_breaks = "1 day") + scale_y_continuous(limits = c(0, 1200), breaks = seq(0, 1200, 300)) + scale_fill_manual(values = col_candidate) + labs(title = "차기 대선주자 트위터 언급량 추이", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), panel.grid.minor.x = element_blank(), panel.grid.minor.y = element_blank()) # y축 보조축 삭제 ``` --- <br><br> <img src="08-project2_files/figure-html/unnamed-chunk-16-1.png" width="80%" style="display: block; margin: auto;" /> --- name: 08-2 class: title1 08-2 SNS 이슈 알아보기 --- ##### 8월 14일의 이슈 알아보기 - 유독 두 후보의 언급량이 많은 8월 14일에 무슨 일이 있었는지 알아보기 ##### 분석 절차 - 1.관심 날짜와 그 외 날짜의 단어 빈도를 구합니다. - 2.로그 오즈비를 이용해 관심 날짜에 상대적으로 많이 사용된 단어를 추출합니다. - 3.트윗의 내용을 살펴보고 관심 날짜에 무슨 일이 있었는지 알아봅니다. --- ##### 1. 띄어쓰기 기준 토큰화 ```r library(tidytext) library(KoNLP) word_tweet_raw <- tweet %>% unnest_tokens(input = text, output = word, token = "words", drop = F) ``` --- ##### 2. 날짜 분류, 단어별 빈도 구하기 ```r frequency14 <- word_tweet_raw %>% mutate(category = ifelse(date == "2020-08-14", "target", "etc")) %>% filter(str_count(word) >= 2) %>% count(category, word, sort = T) frequency14 ``` ``` ## # A tibble: 59,382 x 3 ## category word n ## <chr> <chr> <int> ## 1 etc 이재명 2194 ## 2 etc 이낙연 1928 ## 3 target 이재명 791 ## 4 target 이낙연 651 ## 5 etc 이재명이 650 ## 6 etc 이재명은 507 ## 7 etc 민주당 396 ## 8 etc 의원님 394 ## 9 etc 코로나 349 ## 10 target 이재명이 287 ## # ... with 59,372 more rows ``` --- ##### 3. 로그 오즈비 구하기 - 분모에 `"etc"`, 분자에 `"target"`의 단어 빈도를 놓고 로그 오즈비를 구함 - 관심 날짜에 상대적으로 많이 사용된 단어일수록 `log_odds_ratio`가 큰 값을 지님 ```r # Wide form으로 변환 library(tidyr) wide14 <- frequency14 %>% pivot_wider(names_from = category, values_from = n, values_fill = list(n = 0)) # 로그 오즈비 변수 추가 wide14 <- wide14 %>% mutate(log_odds_ratio = log(((target + 1) / (sum(target + 1))) / ((etc + 1) / (sum(etc + 1))))) # log_odds_ratio 높은 순 출력 wide14 %>% arrange(-log_odds_ratio) %>% head(20) ``` --- - `"조사기관'`, `"선호도'`, `"여론조사"`: 여론조사와 관련된 일이 있었다 ``` ## # A tibble: 20 x 4 ## word etc target log_odds_ratio ## <chr> <int> <int> <dbl> *## 1 조사기관 0 10 3.00 ## 2 댓방 0 9 2.90 ## 3 지지층에서는 0 9 2.90 ## 4 높게 0 8 2.80 ## 5 이재멍 0 7 2.68 ## 6 조국장관을 0 7 2.68 ## 7 권력찬탈 0 6 2.55 ## 8 나가지 0 6 2.55 ## 9 떨어지는데 0 6 2.55 ## 10 맞대응 0 6 2.55 ## 11 선수를 0 6 2.55 *## 12 선호도가 0 6 2.55 *## 13 여론조사는 0 6 2.55 ## 14 이낙연후보는 0 6 2.55 ## 15 이죄명은 0 6 2.55 *## 16 차기선호도 0 6 2.55 ## 17 역선택 1 12 2.47 ## 18 가능성은 0 5 2.39 ## 19 가치인 0 5 2.39 ## 20 고귀한 0 5 2.39 ``` --- ##### 4. 원문 살펴보기 - 2020년 8월 14일에 `"조사"`를 언급한 트윗을 추출해 내용 살펴보기 - 이날 발표된 차기 대선주자 지지도 조사 결과에서 이재명 경기도지사가 이낙연 의 원을 처음으로 역전 .scroll-box-26[ ```r # 트윗 내용 확인 tweet %>% filter(date == "2020-08-14" & str_detect(text, "조사")) %>% head(10) %>% pull(text) ``` ``` ## [1] "서너개로 쪼개져 있던 극보수 정당들의 몰락과 바미당 유승민계를 흡수해서 지지율이 30% 정도 되는 미통당 지지자들이 이낙연 적수가 되는 뚜렷한 대권후보가 없어서 여론조사시 윤석렬과 상대적으로 만만한 이재명을 역선택하고 있는 것이다. 이들은 미통당 유력후보 출현시 다시 돌아갈 표이다." ## [2] "저건 진짜진짜 말도 안됨;;;; 시발 나한테도 지지율조사해가라고 난 아닥하고 이낙연의원님" ## [3] "어차피 갤럽은 누가 잘하고 있는지 묻는게 아니야 요즘 누구 이름 많이 들어봤냐는 인지도 조사라 언플 좀만 해도 1위 금방 가져오는데 언플은 워낙 이낙연 총리님과는 거리가 멀고 당대표 되시면 다시 1위 쉬움. 근데 걱정되는건 그때까지 언론과 당빠들이 연일 공격할거란말야. 상처받으실까 속상.." ## [4] "어느 여론조사에서 이재명지사가 이낙연 후보보다 지지율이 높게 나왔군요 이재명 지사 지지자들에겐 축하를 보내 드립니다. 전 이낙연 이재명 두분 모두 민주당의 자산이니.. 메너있고 슬기러운 경쟁이길 기대해 봅니다" ## [5] "정신을 누가 듣냐며 개무시해놓고 정신 나간다고 욕하는 것들이 있었네. 트친님들 말씀처럼 정신 듣는 사람들은 어차피 이낙연 의원님 뽑을 사람들임. 말도 안되는 여론조사 결과 내면서 공중파에서 쉬지 않고 빨아주는 이재명 생각해서라도 공중파에 많이 나오시길!" ## [6] "여론조사, 이낙연의원의 차기정치지도자 선호도, 이재명이 앞섰다고? 믿어주라고? 개도 안쓰는 쌍욕에 오럴거리는 그가 선호도가 높아? 대한민국 국민이 미쳐간다는거라고? 돈 몇푼에 영혼마저 파는놈들이 기레기놈들 뿐인줄 알았더니 그게 아닌가보구나!" ## [7] "3 글구 더 재미있는건 찢명이 지지율이 이낙연을 앞선게\u314b대구경북과 미통당 그리구 오렌지당이 민 결과\u314b\u314b 못믿겠어?뇌피셜이 아니라 갤럽 세부 조사 분석표 캡쳐한번 봐! 혹여 수구보수까지 찢명이를 지지한다며 확장성 운운 하는새끼는 그냥 모지리 아니면 간악한새끼라 보면됨\u314b 암튼 재밌어" ## [8] "전당대회도 그렇고 진짜 민주당 지지자들은 여론조사 신경 1도 안쓰는 사람 많음. 그냥 이낙연 찍으면 되니까." ## [9] "여론조사에서(신빙성은 없다만) 이재명이 이낙연 눌렀다고 연락왔다. 대선검증가면 탈탈털릴텐데 뭔 자신감이냐" ## [10] "응원합니다 여론조작 전 안믿어요 조금전 당대표 여론조사 번호대로 하면 되지 1번 박주민 2번 김부겸 3번 이낙연 4번 없음 . 장난하나. 최고의원은 1번 어쩌구 7번 김종민. 8번 신승. ? 여하간 끝까지 듣는라 화나네요 여론조사 요새 하루에 3-4번도 받는 날도 있네요 돈은 어디서 나는지." ``` ] --- #### 8월 18일~19일의 이슈 알아보기 - 8월 18일과 19일에 이낙연 의원의 언급량이 크게 상승함 ##### 1. 날짜 분류하고 단어별 빈도 구하기 ```r frequency_nak1819 <- word_tweet_raw %>% mutate(category = ifelse(date >= "2020-08-18" & date <= "2020-08-19", "target", "etc")) %>% filter(candidate == "이낙연" & str_count(word) >= 2) %>% count(category, word, sort = T) ``` --- ##### 2. 로그 오즈비 구하기 ```r # Wide form으로 변환 wide_nak1819 <- frequency_nak1819 %>% pivot_wider(names_from = category, values_from = n, values_fill = list(n = 0)) # 로그 오즈비 변수 추가 wide_nak1819 <- wide_nak1819 %>% mutate(log_odds_ratio = log(((target + 1) / (sum(target + 1))) / ((etc + 1) / (sum(etc + 1))))) ``` --- - `"음성판정"`, `"검사결과"`: 이낙연 의원에게 코로나19 검사와 관련된 일이 있었다 .scroll-box-26[ ```r # log_odds_ratio 높은 순 출력 wide_nak1819 %>% arrange(-log_odds_ratio) %>% head(20) ``` ``` ## # A tibble: 20 x 4 ## word etc target ## <chr> <int> <int> ## 1 다행입니다 0 41 ## 2 음성판정 0 39 ## 3 cbs 3 127 ## 4 마이크 0 29 ## 5 음성 4 137 ## 6 무탈하시길 0 23 ## 7 일부러 0 16 ## 8 아무일 0 15 ## 9 밤새 0 14 ## 10 확진자가 0 13 ## 11 검사 2 38 ## 12 기도합니다 0 12 ## 13 검사결과 0 11 ## 14 무사하시길 0 11 ## 15 차명진 0 11 ## 16 판정 2 33 ## 17 방송국 0 10 ## 18 잠이 0 10 ## 19 ㅜㅜ 2 30 ## 20 김정훈 0 9 ## log_odds_ratio ## <dbl> ## 1 4.09 ## 2 4.05 ## 3 3.82 ## 4 3.76 ## 5 3.68 ## 6 3.54 ## 7 3.19 ## 8 3.13 ## 9 3.07 ## 10 3.00 ## 11 2.92 ## 12 2.92 ## 13 2.84 ## 14 2.84 ## 15 2.84 ## 16 2.78 ## 17 2.76 ## 18 2.76 ## 19 2.69 ## 20 2.66 ``` ] --- ##### 3. 원문 살펴보기 - 로그 오즈비가 가장 높은 `"다행입니다"`를 언급한 트윗 살펴보기 - 이낙연 의원이 코로나19 검사 음성 판정을 받았음 .scroll-box-26[ ```r # 트윗 내용 확인 tweet %>% filter(date >= "2020-08-18" & date <= "2020-08-19" & candidate == "이낙연" & str_detect(text, "다행입니다")) %>% head(10) %>% pull(text) ``` ``` ## [1] "이낙연 의원님 음성이신가 보다. 너무 잘됐고 감사한 일. 정말 다행입니다." ## [2] "이낙연 의원님. 음성판정. 정말 다행입니다. 가슴을 쓸어내렸습니다. 더더욱 우리 모두 조심해야겠습니다." ## [3] "이낙연 음성♥♥♥ 정말 다행입니다~" ## [4] "다행입니다 조마 조마하면 가슴 졸였을 수 많은 사람들과 음성 나오길 기도 드린 여러분들이 계시기에 고맙습니다 자가격리 잘하십시요 간간히 소식 올려주시구요~^^ 이낙연 의원님 건강하셔서 감사합니다" ## [5] "다행입니다. 결과와는 별개로 cbs행태가 고약하네요. 방송 하실 때 꼭 마스크 쓰세요. #이낙연_당대표" ## [6] "리) 일단 천만다행입니다... 이낙연 의원 검사 받았다는 소식 듣고 어젯밤 잠 못 주무신 분들도 있으셨을듯..." ## [7] "음성 나와서 다행입니다 앞으로 이낙연 의원님 방송국과 인터뷰하실때도 마스크 쓰게 해주시고 사람들과 악수도 당분간 삼가해주세요 방송국 출연할때 출연진들도 잘살펴봐주세요 이낙연의원님 안계시는 민주당과 2년후 대한민국은 암울합니다 \u315c\u315c" ## [8] "결과 음성 나오셨다니 다행입니다...이낙연의원님의 몸은 개인의 몸이 아닙니다...모든국민의 몸입니다 건강에 신경써 주세요~~" ## [9] "이낙연 의원님 정말 마음 졸였는데 음성 나와 다행입니다 천만 다행입니다" ## [10] "이낙연 의원 보좌진을 욕했지만 의원님도 원망에서 자유롭진 않습니다. 지금까지 맘졸인거 생각하면 그렇습니다. 정말 다행입니다." ``` ] --- name: 08-3 class: title1 08-3 감정 단어 살펴보기 --- ##### 분석 절차 - 1.트윗에 감정 점수를 부여한 다음 감정 범주로 분류합니다. - 2.감정 범주별로 자주 언급한 단어를 추출해 막대 그래프를 만듭니다. #### 감정 단어 살펴보기 ##### 1. 감정 점수, 감정 범주 부여하기 ```r # 감정 사전 불러오기 dic <- read_csv("files/knu_sentiment_lexicon.csv") # 감정 점수 부여, 감정 극성 분류 word_tweet <- word_tweet_raw %>% left_join(dic, by = "word") %>% # 감정 점수 부여 mutate(polarity = ifelse(is.na(polarity), 0, polarity), # NA를 0으로 변환 sentiment = ifelse(polarity == 2, "긍정", # 감정 범주 분류 ifelse(polarity == -2, "부정", "중립"))) ``` --- ##### 2. 자주 언급한 감정 단어 살펴보기 - 후보 이름은 가장 많이 언급되지만 트윗 해석에 도움 안되므로 제거 ```r # 자주 언급한 단어 추출 top10_word <- word_tweet %>% # 불용어 제거 filter(!(candidate == "이낙연" & str_detect(word, "이낙연")) & !(candidate == "이재명" & str_detect(word, "이재명"))) %>% filter(str_count(word) >= 2) %>% count(candidate, sentiment, word) %>% group_by(candidate, sentiment) %>% slice_max(n, n = 10, with_ties = F) top10_word ``` --- ``` ## # A tibble: 60 x 4 ## # Groups: candidate, ## # sentiment [6] ## candidate sentiment ## <chr> <chr> ## 1 이낙연 긍정 ## 2 이낙연 긍정 ## 3 이낙연 긍정 ## 4 이낙연 긍정 ## 5 이낙연 긍정 ## 6 이낙연 긍정 ## 7 이낙연 긍정 ## 8 이낙연 긍정 ## 9 이낙연 긍정 ## 10 이낙연 긍정 ## word n ## <chr> <int> ## 1 좋은 32 ## 2 소중한 11 ## 3 좋다 11 ## 4 감사 8 ## 5 많다 8 ## 6 좋아하는 8 ## 7 최고 8 ## 8 훌륭한 8 ## 9 최고의 7 ## 10 좋아 6 ## # ... with 50 more rows ``` --- ##### 3. 막대 그래프 만들기 ```r ggplot(top10_word, aes(x = reorder_within(word, n, candidate), y = n, fill = sentiment)) + geom_col() + coord_flip() + facet_wrap(candidate ~ sentiment, # 후보, 감정 범주별 그래프 생성 scales = "free") + scale_x_reordered() ``` --- <br> ![](08-project2_files/figure-html/unnamed-chunk-28-1.png)<!-- --> --- ##### 그래프 다듬기 ```r col_sentiment <- c("#619CFF", "#00BA38", "#F8766D") # 감정 색깔 목록 order_sentiment <- c("긍정", "중립", "부정") # 감정 범주 목록 # 그래프 순서 지정 top10_word$sentiment <- factor(top10_word$sentiment, levels = order_sentiment) ``` --- ##### 그래프 다듬기 ```r ggplot(top10_word, aes(x = reorder_within(word, n, candidate), y = n, fill = sentiment)) + geom_col() + coord_flip() + facet_wrap(candidate ~ sentiment, scales = "free") + scale_x_reordered() + scale_fill_manual(values = col_sentiment) + labs(title = "차기 대선주자 감정 단어", subtitle = "감정 극성별 빈도 Top 10", x = NULL, y = NULL, fill = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), legend.position = "bottom") # 범례 위치 ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-30-1.png" width="65%" style="display: block; margin: auto;" /> --- name: 08 class: title1 08-4 감정 경향 살펴보기 --- #### 두 후보를 언급한 트윗이 전반적으로 어떤 감정 경향을 띠는지 알아보기 ##### 분석 절차 - 1.트윗의 감정 점수로 히스토그램과 확률 밀도 함수 그래프를 만들어 분포를 살펴봅니다. - 2.확률 밀도 함수 그래프를 날짜별로 만들어 트윗의 감정 점수 분포가 날짜에 따라 어떻게 다른지 <br> 살펴봅니다. - 3.감정 범주별 빈도와 비율을 막대 그래프로 만들어 어떤 감정을 담은 트윗이 많은지 살펴봅니다 --- #### 전반적인 감정 경향 살펴보기 ```r # 트윗 감정 점수 구하기 sentiment_tweet <- word_tweet %>% group_by(candidate, status_id) %>% summarise(score = sum(polarity)) %>% ungroup() # 트윗 원문에 감정 점수 결합 tweet <- tweet %>% left_join(sentiment_tweet, by = c("candidate", "status_id")) # 감정 점수 히스토그램 hist(tweet$score) ``` --- <br> <img src="08-project2_files/figure-html/unnamed-chunk-33-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 확률 밀도 함수 그래프 만들기 - 확률 밀도 함수 그래프(density plot)를 만들어 전반적으로 어떤 감정을 담은 트윗이 많은지 살펴보기 - `geom_density()` - `adjust`: 는 띠 너비(bandwidth)를 조정해 그래프를 평평하게 만들기 - `alpha`: 투명도를 조정해 그래프 중첩된 부분 드러내기 ```r ggplot(tweet, aes(x = score, fill = candidate)) + geom_density(adjust = 2, alpha = 0.6) ``` <img src="08-project2_files/figure-html/unnamed-chunk-34-1.png" width="48%" /> --- ##### 그래프 다듬기 ```r ggplot(tweet, aes(x = score, fill = candidate)) + geom_density(adjust = 2, alpha = 0.6) + geom_vline(xintercept = 0, # 0점 위 세로선 표시 linetype = "dashed", # 점선 표시 size = 0.5, alpha = 0.5) + scale_x_continuous(breaks = c(-5:5), # x축 범위 limits = c(-5, 5)) + # x축 간격 scale_fill_manual(values = col_candidate) + labs(title = "차기 대선주자 감정 점수 분포", subtitle = "2020.8.13 ~ 2020.8.21", y = NULL, fill = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), legend.position = "bottom", panel.grid = element_blank()) # 격자 삭제 ``` --- <br10> <img src="08-project2_files/figure-html/unnamed-chunk-35-1.png" width="70%" style="display: block; margin: auto;" /> - 이재명 경기도지사는 이낙연 의원에 비해 감정 점수가 낮거나 0에 가까운 트윗이 많다 - 이낙연 의원은 이재명 경기도지사에 비해 감정 점수가 높은 트윗이 많다 --- #### 일자별 감정 경향 살펴보기 ##### 일자별 확률 밀도 함수 그래프 만들기 ```r ggplot(tweet, aes(x = score, fill = candidate)) + geom_density() + facet_wrap(~ date) ``` <img src="08-project2_files/figure-html/unnamed-chunk-36-1.png" width="70%" /> --- ##### 그래프 다듬기(1/2) ```r ggplot(tweet, aes(x = score, fill = candidate)) + geom_density(adjust = 2, alpha = 0.6) + geom_vline(xintercept = 0, linetype = "dashed", size = 0.5, alpha = 0.5) + facet_wrap(~ str_remove(date, "2020-"), # x축 년도 삭제 scales = "free_y", ncol = 3, strip.position = "bottom") + scale_x_continuous(breaks = c(-5:5), limits = c(-5, 5)) + scale_fill_manual(values = col_candidate) + ``` --- ##### 그래프 다듬기(2/2) ```r labs(title = "차기 대선주자 일자별 감정 점수 분포", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + theme_bw(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), legend.position = "bottom", panel.grid = element_blank(), axis.ticks = element_blank(), # 축 눈금 삭제 axis.text = element_blank(), # 축 삭제 strip.background = element_rect(colour = "black", # 패널명 배경 fill = "white")) ``` --- <img src="08-project2_files/figure-html/p_tweet_density-1.png" width="80%" style="display: block; margin: auto;" /> --- - 대부분 이낙연 의원은 긍정 트윗, 이재명 경기도지사는 부정 트윗이 많다 - 8월 16일, 17일: 이낙연 의원을 긍정적으로 언급한 트윗이 많다 - 8월 18일 - 이낙연 의원은 감정 점수가 낮거나 0점에 가까운 트윗이 많다 - 이재명 경기도지사는 감정 점수가 높은 트윗이 많다 <img src="08-project2_files/figure-html/unnamed-chunk-39-1.png" width="50%" style="display: block; margin: auto;" /> --- .box[ .info[<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FF7333;"> [ comment ] <path d="M505.12019,19.09375c-1.18945-5.53125-6.65819-11-12.207-12.1875C460.716,0,435.507,0,410.40747,0,307.17523,0,245.26909,55.20312,199.05238,128H94.83772c-16.34763.01562-35.55658,11.875-42.88664,26.48438L2.51562,253.29688A28.4,28.4,0,0,0,0,264a24.00867,24.00867,0,0,0,24.00582,24H127.81618l-22.47457,22.46875c-11.36521,11.36133-12.99607,32.25781,0,45.25L156.24582,406.625c11.15623,11.1875,32.15619,13.15625,45.27726,0l22.47457-22.46875V488a24.00867,24.00867,0,0,0,24.00581,24,28.55934,28.55934,0,0,0,10.707-2.51562l98.72834-49.39063c14.62888-7.29687,26.50776-26.5,26.50776-42.85937V312.79688c72.59753-46.3125,128.03493-108.40626,128.03493-211.09376C512.07526,76.5,512.07526,51.29688,505.12019,19.09375ZM384.04033,168A40,40,0,1,1,424.05,128,40.02322,40.02322,0,0,1,384.04033,168Z"></path></svg> 감정 점수는 조심해서 해석해야 합니다] - 특정 후보를 언급한 트윗의 감정 점수가 낮다고 해서 후보를 비판한 트윗이 많다고 할 수는 없다 - 단지 부정적인 감정을 표현하는 단어를 사용한 트윗이 많을 수도 있음 - 8월 18일~19일 - 이낙연 의원이 코로나19에 감염되었을까 봐 걱정하는 트윗이 많았음 - '걱정', '불안'처럼 부정적인 감정 표현 단어 사용해서 감정 점수가 낮은 것. 비판 X - 감정 점수만으로는 글쓴이가 무엇을 부정적으로 언급했는지 알 수 없기 때문에 해석 조심해야함 ] --- #### 감정 범주 살펴보기 ##### 1. 감정 범주별 빈도와 비율 구하기 ```r # 감정 분류 변수 생성 tweet <- tweet %>% mutate(sentiment = ifelse(score >= 1, "긍정", ifelse(score <= -1, "부정", "중립"))) # 후보, 감정별 빈도 및 비율 frequency_sentiment <- tweet %>% group_by(candidate) %>% count(sentiment) %>% mutate(ratio = n/sum(n)) frequency_sentiment ``` --- ``` ## # A tibble: 6 x 4 ## # Groups: candidate [2] ## candidate sentiment n ## <chr> <chr> <int> ## 1 이낙연 긍정 577 ## 2 이낙연 부정 612 ## 3 이낙연 중립 2060 ## 4 이재명 긍정 723 ## 5 이재명 부정 1068 ## 6 이재명 중립 3297 ## ratio ## <dbl> ## 1 0.178 ## 2 0.188 ## 3 0.634 ## 4 0.142 ## 5 0.210 ## 6 0.648 ``` --- ##### 2. 감정 범주 빈도 막대 그래프 만들기 ```r ggplot(frequency_sentiment, aes(x = sentiment, y = n, fill = sentiment)) + geom_col() + facet_wrap(~ candidate) ``` <img src="08-project2_files/figure-html/unnamed-chunk-41-1.png" width="70%" /> --- ##### 그래프 다듬기 ```r # 순서 설정 frequency_sentiment$sentiment <- factor(frequency_sentiment$sentiment, levels = order_sentiment) ``` --- ##### 그래프 다듬기 ```r library(scales) ggplot(frequency_sentiment, aes(x = sentiment, y = n, fill = sentiment)) + geom_col(show.legend = F) + facet_wrap(~ candidate) + geom_text(aes(label = comma(n)), vjust = -0.5) + ylim(0, 3500) + scale_fill_manual(values = col_sentiment) + # 막대 색깔 labs(title = "차기 대선주자 트윗 감정 빈도", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL) + theme_bw(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), axis.text.y = element_blank(), axis.ticks.y = element_blank(), panel.grid = element_blank()) ``` --- <br><br> <img src="08-project2_files/figure-html/unnamed-chunk-43-1.png" width="80%" style="display: block; margin: auto;" /> --- ##### 3. 감정 범주 비율 누적 막대 그래프 만들기 ```r ggplot(frequency_sentiment, aes(x = candidate, y = ratio, fill = sentiment)) + geom_col() ``` <img src="08-project2_files/figure-html/unnamed-chunk-44-1.png" width="60%" /> --- ##### 그래프 다듬기(1/2) ```r # 막대 누적 순서 지정 frequency_sentiment$sentiment <- factor(frequency_sentiment$sentiment, levels = rev(order_sentiment)) ggplot(frequency_sentiment, aes(x = candidate, y = ratio, fill = sentiment)) + geom_col(show.legend = F, width = 0.7) + geom_text(aes(label = paste(sentiment, percent(ratio, accuracy = 0.1))), position = position_stack(vjust = 0.5)) + # 수직 위치 coord_flip() + scale_x_discrete(limits = c("이재명", "이낙연")) + labs(title = "차기 대선주자 트윗 감정 비율", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + ``` --- ##### 그래프 다듬기(2/2) ```r theme_void(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), legend.position = "bottom", axis.text.y = element_text(size = 12), # y축 글자 크기 plot.margin = margin(1, 1, 1, 1, unit = "line")) # 여백 상우하좌, 단위 ``` <svg viewBox="0 0 352 512" xmlns="http://www.w3.org/2000/svg" style="height:1em;fill:currentColor;position:relative;display:inline-block;top:.1em;"> [ comment ] <path d="M176 80c-52.94 0-96 43.06-96 96 0 8.84 7.16 16 16 16s16-7.16 16-16c0-35.3 28.72-64 64-64 8.84 0 16-7.16 16-16s-7.16-16-16-16zM96.06 459.17c0 3.15.93 6.22 2.68 8.84l24.51 36.84c2.97 4.46 7.97 7.14 13.32 7.14h78.85c5.36 0 10.36-2.68 13.32-7.14l24.51-36.84c1.74-2.62 2.67-5.7 2.68-8.84l.05-43.18H96.02l.04 43.18zM176 0C73.72 0 0 82.97 0 176c0 44.37 16.45 84.85 43.56 115.78 16.64 18.99 42.74 58.8 52.42 92.16v.06h48v-.12c-.01-4.77-.72-9.51-2.15-14.07-5.59-17.81-22.82-64.77-62.17-109.67-20.54-23.43-31.52-53.15-31.61-84.14-.2-73.64 59.67-128 127.95-128 70.58 0 128 57.42 128 128 0 30.97-11.24 60.85-31.65 84.14-39.11 44.61-56.42 91.47-62.1 109.46a47.507 47.507 0 0 0-2.22 14.3v.1h48v-.05c9.68-33.37 35.78-73.18 52.42-92.16C335.55 260.85 352 220.37 352 176 352 78.8 273.2 0 176 0z"></path></svg> `geom_text()`에 입력한 `percent()`: 값에 %를 붙여 비율로 표현하는 `scale` 패키지 함수. <br> `accuracy`는 반올림할 자릿수를 정하는 기능. --- <br><br><br> <img src="08-project2_files/figure-html/unnamed-chunk-47-1.png" width="70%" style="display: block; margin: auto;" /> --- name: 08-5 class: title1 08-5 감정 추이 살펴보기 --- ##### 분석 절차 - 1.날짜, 후보, 감정 범주별로 트윗의 빈도를 구합니다. - 2.선 그래프와 영역 차트를 만들어 추이를 살펴봅니다. --- #### 트윗 감정 추이 선 그래프 만들기 ```r # 날짜, 후보, 감정별 빈도 sentiment_candidate <- tweet %>% count(date, candidate, sentiment) sentiment_candidate ``` ``` ## # A tibble: 54 x 4 ## date candidate ## <date> <chr> ## 1 2020-08-13 이낙연 ## 2 2020-08-13 이낙연 ## 3 2020-08-13 이낙연 ## 4 2020-08-13 이재명 ## 5 2020-08-13 이재명 ## 6 2020-08-13 이재명 ## 7 2020-08-14 이낙연 ## 8 2020-08-14 이낙연 ## 9 2020-08-14 이낙연 ## 10 2020-08-14 이재명 ## sentiment n ## <chr> <int> ## 1 긍정 55 ## 2 부정 36 ## 3 중립 156 ## 4 긍정 113 ## 5 부정 143 ## 6 중립 383 ## 7 긍정 121 ## 8 부정 139 ## 9 중립 449 ## 10 긍정 191 ## # ... with 44 more rows ``` --- ```r ## 트윗 감정 추이 선 그래프 ggplot(sentiment_candidate, aes(x = date, y = n, col = sentiment)) + geom_line() + geom_point() + facet_wrap(~ candidate, nrow = 2, scales = "free_x") ``` <img src="08-project2_files/figure-html/unnamed-chunk-49-1.png" width="50%" /> --- ##### 중립 트윗 제외하고 다시 만들기 ```r # 중립 트윗 제외 tweet_polar <- sentiment_candidate %>% filter(sentiment != "중립") ggplot(tweet_polar, aes(x = date, y = n, col = sentiment)) + geom_line() + geom_point() + facet_wrap(~ candidate, nrow = 2, scales = "free_x") ``` <img src="08-project2_files/figure-html/p_tweet_polar_line-1.png" width="38%" /> --- <img src="08-project2_files/figure-html/unnamed-chunk-50-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 그래프 다듬기(1/2) ```r # 색깔 목록 생성 col_polar <- c("#619CFF", "#F8766D") ggplot(tweet_polar, aes(x = date, y = n, col = sentiment)) + geom_line(size = 1) + geom_point(size = 2) + facet_wrap(~ candidate, nrow = 2, scales = "free_x") + scale_x_date(date_labels = "%m/%d", date_breaks = "1 day") + ylim(0, 250) + ``` --- ##### 그래프 다듬기(2/2) ```r scale_color_manual(values = col_polar) + labs(title = "차기 대선주자 트윗 감정 추이", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, col = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), panel.grid.minor.x = element_blank(), panel.spacing = unit(2, "lines")) # 그래프 간격 ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-53-1.png" width="70%" style="display: block; margin: auto;" /> --- #### 트윗 감정 추이 영역 차트 만들기 ```r ggplot(tweet_polar, aes(x = date, y = n, fill = sentiment)) + geom_area(position = "dodge", alpha = 0.7) + facet_wrap(~ candidate, nrow = 2, scales = "free_x") ``` <img src="08-project2_files/figure-html/unnamed-chunk-54-1.png" width="50%" /> --- ##### 그래프 다듬기 ```r ggplot(tweet_polar, aes(x = date, y = n, fill = sentiment)) + geom_area(position = "dodge", alpha = 0.7) + facet_wrap(~ candidate, nrow = 2, scales = "free_x") + scale_x_date(date_labels = "%m/%d", date_breaks = "1 day") + ylim(0, 250) + scale_fill_manual(values = col_polar) + labs(title = "차기 대선주자 트윗 감정 추이", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + theme_gray(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12), panel.grid = element_blank(), panel.spacing = unit(2, "lines")) # 그래프 간격 띄우기 ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-55-1.png" width="70%" style="display: block; margin: auto;" /> --- name: 08-6 class: title1 08-6 긍정, 부정 트윗 단어 비교하기 --- ##### 분석 절차 - 1.감정 범주 및 단어별 빈도를 구합니다. - 2.로그 오즈비를 구한 다음 두 후보자의 주요 긍정 단어와 부정 단어를 추출합니다. - 3.막대 그래프와 롤리팝 차트를 만들어 주요 단어를 비교합니다. --- #### 긍정 트윗 주요 단어 비교하기 ##### 1. 감정 범주 및 단어별 빈도 구하기 <br-10> .scroll-box-24[ ```r # 두 글자 이상 한글 단어 추출 word_sentiment_tweet <- word_tweet_raw %>% filter(str_detect(word, "[가-힣]") & str_count(word) >= 2) %>% # tweet 결합 left_join(tweet %>% select(candidate, status_id, score, sentiment), by = c("candidate", "status_id")) glimpse(word_sentiment_tweet) ``` ``` ## Rows: 138,142 ## Columns: 9 ## $ status_id <dbl> 1.293765e+18, 1.293765e+18, 1.29376... ## $ screen_name <chr> "0o0o0o0o0125", "0o0o0o0o0125", "0o... ## $ created_at <dttm> 2020-08-13 04:23:35, 2020-08-13 04... ## $ text <chr> "\"나 채식주의잔데 지금 치킨먹고싶다\" 한편 나라가 디비진다... ## $ candidate <chr> "이낙연", "이낙연", "이낙연", "이낙연", "이낙연", ... ## $ date <date> 2020-08-13, 2020-08-13, 2020-08-13... ## $ word <chr> "채식주의잔데", "지금", "치킨먹고싶다", "한편", "나라... ## $ score <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ sentiment <chr> "중립", "중립", "중립", "중립", "중립", "중립",... ``` ] --- ```r # 감정 범주 및 단어별 빈도 구하기 frequency_sentiment <- word_sentiment_tweet %>% group_by(status_id) %>% # 트윗별 분리 distinct(word, .keep_all = T) %>% # 중복 단어 제거 ungroup() %>% count(candidate, sentiment, word, sort = T) frequency_sentiment ``` ``` ## # A tibble: 72,220 x 4 ## candidate sentiment word n ## <chr> <chr> <chr> <int> ## 1 이재명 중립 이재명 1413 ## 2 이낙연 중립 이낙연 1242 ## 3 이재명 부정 이재명 474 ## 4 이재명 중립 이재명이 456 ## 5 이낙연 부정 이낙연 396 ## 6 이낙연 긍정 이낙연 366 ## 7 이재명 중립 이재명은 333 ## 8 이재명 긍정 이재명 305 ## 9 이낙연 중립 의원님 229 ## 10 이재명 부정 이재명이 172 ## # ... with 72,210 more rows ``` ##### 2. 로그 오즈비 구하기 - `frequency_sentiment`에서 긍정 트윗만 추출 - 후보 이름은 빈도는 높지만 해석하는 데 도움이 되지 않으므로 제거 - 로그 오즈비 구하기 - 분모에 이재명 경기도지사, 분자에 이낙연 의원의 단어 빈도 - 이낙연 의원 언급 트윗에서 상대적으로 많이 사용된 단어일수록 큰 값 ```r # Wide form으로 변환 wide_pos <- frequency_sentiment %>% filter(sentiment == "긍정" & !str_detect(word, "이낙연|이재명")) %>% pivot_wider(names_from = candidate, values_from = n, values_fill = list(n = 0)) # 로그 오즈비 구하기 log_odds_pos <- wide_pos %>% mutate(log_odds_ratio = log(((이낙연 + 1) / (sum(이낙연 + 1))) / ((이재명 + 1) / (sum(이재명 + 1))))) ``` --- ##### 3. 불용어 목록 만들기 <br-10> .scroll-box-26[ ```r # 불용어 확인 log_odds_pos %>% group_by(candidate = ifelse(log_odds_ratio > 0, "이낙연", "이재명")) %>% slice_max(abs(log_odds_ratio), n = 15, with_ties = F) %>% select(word) ``` ``` ## # A tibble: 30 x 2 ## # Groups: candidate [2] ## candidate word ## <chr> <chr> ## 1 이낙연 음성 ## 2 이낙연 의원님 ## 3 이낙연 자가격리 ## 4 이낙연 당대표 ## 5 이낙연 의원은 ## 6 이낙연 당대표가 ## 7 이낙연 정치신세계 ## 8 이낙연 김종민 ## 9 이낙연 반드시 ## 10 이낙연 모습 ## 11 이낙연 의원 ## 12 이낙연 의원이 ## 13 이낙연 의원을 ## 14 이낙연 지지합니다 ## 15 이낙연 총리님 ## 16 이재명 경기도 ## 17 이재명 이익을 ## 18 이재명 경기도는 ## 19 이재명 그는 ## 20 이재명 돈을 ## 21 이재명 지사가 ## 22 이재명 그건 ## 23 이재명 돈이 ## 24 이재명 박원순 ## 25 이재명 진정한 ## 26 이재명 강하게 ## 27 이재명 것이고 ## 28 이재명 공정의 ## 29 이재명 공지영 ## 30 이재명 기본소득 ``` ] --- ##### 3. 불용어 목록 만들기 ```r # 불용어 목록 생성 stopword_pos <- c("것이고", "그건", "그는") ``` --- ##### 4. 막대 그래프 만들기 ```r # 로그 오즈비 상하위 10개 단어 추출 top10_pos <- log_odds_pos %>% filter(!word %in% stopword_pos) %>% group_by(candidate = ifelse(log_odds_ratio > 0, "이낙연", "이재명")) %>% slice_max(abs(log_odds_ratio), n = 10, with_ties = F) # 막대 그래프 생성 ggplot(top10_pos, aes(x = reorder(word, log_odds_ratio), y = log_odds_ratio, fill = candidate)) + geom_col() + coord_flip() ``` <img src="08-project2_files/figure-html/p_top10_pos_bar-1.png" width="30%" /> --- <img src="08-project2_files/figure-html/unnamed-chunk-61-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 그래프 다듬기 ```r ggplot(top10_pos, aes(x = reorder(word, log_odds_ratio), y = log_odds_ratio, fill = candidate)) + geom_col() + coord_flip() + scale_fill_manual(values = col_candidate) + labs(title = "차기 대선주자 긍정 트윗 주요 단어", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12)) ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-62-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 5. 롤리팝 차트(lollipop chart) 만들기 - 선분과 점을 이용해 막대 사탕 모양으로 만든 그래프 - 막대 끝을 도드라지게 표현하기 때문에 여러 값의 차이 나타낼 때 유용 - geom_segment(): x, y축의 시작점과 끝점을 선분으로 연결 ```r # 단어 순서 지정해 factor 타입으로 변환 top10_pos <- top10_pos %>% ungroup() %>% mutate(word = reorder(word, log_odds_ratio)) # 롤리팝 차트 생성 ggplot(top10_pos, aes(x = word, y = log_odds_ratio, col = candidate)) + geom_segment(aes(x = word, # x축 시작점 xend = word, # x축 끝점 y = 0, # y축 시작점 yend = log_odds_ratio)) + # y축 끝점 geom_point() + coord_flip() ``` <img src="08-project2_files/figure-html/p_top10_pos_pop_raw-1.png" width="50%" /> --- <img src="08-project2_files/figure-html/unnamed-chunk-63-1.png" width="70%" style="display: block; margin: auto;" /> --- <br-back-20> ##### 그래프 다듬기 ```r ggplot(top10_pos, aes(x = word, y = log_odds_ratio, col = candidate)) + geom_segment(aes(x = word, xend = word, y = 0, yend = log_odds_ratio), size = 1.1) + geom_point(size = 3.5) + coord_flip() + scale_color_manual(values = col_candidate) + labs(title = "차기 대선주자 긍정 트윗 주요 단어", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, col = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12)) ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-64-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 6. 원문 살펴보기 - `find_word()` 함수 만들기 ```r find_word <- function(df, x, keyword, n = 6) { # 스타일 함수 설정 font <- combine_styles(make_style("ivory"), make_style("deeppink", bg = TRUE), make_style("bold")) # 키워드 추출해 스타일 적용 df %>% filter(str_detect({{x}}, keyword)) %>% # 키워드 추출 head(n) %>% # n행 추출 mutate(x = paste0("[", row_number(), "] ", {{x}}), # 행번호 삽입 x = paste0(str_replace_all(x, keyword, font(keyword)))) %>% # 스타일 적용 pull(x) %>% # 텍스트 추출 cat(sep = "\n\n") # 줄바꿈 출력 } ``` --- ##### 6.1 이낙연 의원 긍정 트윗 ```r # 이낙연 의원 긍정 트윗 추출 pos_nak <- tweet %>% filter(sentiment == "긍정" & candidate == "이낙연") %>% arrange(-score) ``` --- - **"음성"** : 이낙연 의원이 코로나19 검사 결과 음성 판정을 받아 다행이라는 내용 ```r pos_nak %>% find_word(x = text, keyword = "음성") ``` <pre class="r-output"><code>## [1] 매일 좋은 일 3가지 (2020.08.19) 1. 이낙연 총리님의 코로나 검사 결과가 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span>으로 나왔다. 혼자 몸이 아니라 민주당을 바꾸고 대통령님을 도와 다음 정권까지 이어가야할 분이란 걸 새삼 느낀 하루였다. 2, 3 오늘은 1번 하나로 충분하다.<br>##<br>## [2] 의원님 셔츠가 트렌디합니다. 멋진 당대표님을 갖게 될 거라는 희망이 무럭무럭 자라고 있습니다. 슬기로운 자가격리동안 많은 구상이 기대됩니다. 그러나 살살 쉬어가면서도 해주셔도 됩니다요. </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span>이라는 뉴스에 얼마나 기뻤던지요. 요즈음 기쁜 소식은 이낙연의원님으로부터 옵니다.<br>##<br>## [3] 아침에 일어나자마자 이낙연 후보님 뉴스를 접하고 아내와 땅이 꺼져라 한숨 쉬면서 생각나는 여러가지 걱정거리를 얘기하다 출근했고 퇴근 전 전화했다가 "</span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span>판정 나셔서 다행이다"며 서로 위안하다 끊었다. 그 분과 대통령님은 이역만리의 우리 삶과 행복을 지키는 소중한 분들이시다. </span></code></pre> --- - **"의원님"** : 이낙연 의원을 응원하는 내용 ```r pos_nak %>% find_word(x = text, keyword = "의원님") ``` <pre class="r-output"><code>## [1] 이낙연 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>! 우리사회에서 정치인들의 보기좋은 경쟁을 보기힘드네요 이낙연과 이재명의 정책비전을 국민들께서 판단할수 있도록 아름다운 경쟁을 국민들께서 행복한 선택의 기회를 할수있도록 참 좋은 정치를 해주세요 늘 두분께 관심과 지지를 표합니다<br>##<br>## [2] 어제 검사한 이낙연</span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span> 결과가 아침 일찍 나오는거 보고 새삼 k-진단에 대해 감탄. 그간 기술적인 부분만 감탄했다면 이번엔 심리적인 부분에서 더더 감탄. 3일~7일 걸렸음 탐라의 오소리님들 다 넉다운 됐을듯.<br>##<br>## [3] </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span> 셔츠가 트렌디합니다. 멋진 당대표님을 갖게 될 거라는 희망이 무럭무럭 자라고 있습니다. 슬기로운 자가격리동안 많은 구상이 기대됩니다. 그러나 살살 쉬어가면서도 해주셔도 됩니다요. 음성이라는 뉴스에 얼마나 기뻤던지요. 요즈음 기쁜 소식은 이낙연</span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>으로부터 옵니다. </span></code></pre> --- ##### 6.2 이재명 경기도지사 긍정 트윗 ```r # 이재명 경기도지사 긍정 트윗 추출 pos_jae <- tweet %>% filter(sentiment == "긍정" & candidate == "이재명") %>% arrange(-score) ``` --- - **"경기도"** : 이재명 경기도지사가 경기도에서 시행한 정책을 다룬 내용 ```r pos_jae %>% find_word(x = text, keyword = "경기도") ``` <pre class="r-output"><code>## [1] 중대본과 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>의 워딩이 분명한 온도차이긴 한데 곱게 말해서 들을까 하는 생각이 먼저 든다. 이재명은 늘 이렇게 고압적이고 폭력적이다며 까대던데 솔직히 곱게 말해서 들어쳐먹냐 이거지 복잡한 생각이 들었다<br>##<br>## [2] "공정한 사회, 공정한 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>"??? 앞에 몇글자가 생략 되었죠? "이재명에게만 공정한 사회" "이재명에게만 공정한 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>" 이게 원문 아닐까요? ㅋㅋㅋ<br>##<br>## [3] 인물열전] 이재명에게서 노무현을 보다…“진짜 민주주의를 향한 위대한 발걸음” 온라인 | 20.08.13 01:44 손시권 경인본부 기자 손시권 기자님 어디 계시죠? </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>청인가요??? ppl도 뉴스처럼 광고하는거 잘 봤어요 </span></code></pre> --- - **"이익을"** : 이재명 경기도지사와 관련된 정치적 이익을 다룬 내용 ```r pos_jae %>% find_word(x = text, keyword = "이익을") ``` <pre class="r-output"><code>## [1] 맞는 말씀 부동산 기득권층의 심기를 건든건 이재명지사죠 불로소득이 줄수록 기득권층은 수익이 주니까요 기득권이란 말 그대로 특정 영역을 선점해 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>이익을</span><span> 착취해가는 집단들이죠 지역의 땅부자나 재벌들 부동산과 돈놀이로 수백억씩 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>이익을</span><span> 내며 일하지 않고 돈버는 사람들이니까요<br>##<br>## [2] 현재 대한민국에서 답없는 것들 교회 이재명 윤석열 미통당 기레기 일베 이새끼들은 코로나와 수해에는 신경도 안쓰고 자신들의 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>이익을</span><span> 위해서 오늘도 열심히 짖는다<br>##<br>## [3] 언제나 정권의 위기를 틈타 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>이익을</span><span> 취하던 김어준이었기에 이번엔 이재명과 손잡고 전광훈을 고용하여 이번 사태를 저질렀다고 생각하는 사람이 충분히 많이 있을것 같아요. 김어준 추종자들이 더 그렇게 생각할것 같군요. </span></code></pre> --- - `"이익을"` - 긍정 트윗에서 추출했는데도 부정적인 내용이 많이 포함됨 - 이낙연 의원에 비해 이재명 경기도지사의 트윗에 상대적으로 자주 사용되어 주요 단어로 추출됐지만 이 단어가 사용된 트윗의 감정 점수가 높지는 않음 - 언급한 트윗의 감정 점수가 언급하지 않은 트윗보다 전반적으로 낮음 .scroll-box-20[ .pull-left[ ```r # "이익을" 언급한 트윗 pos_jae %>% filter( str_detect(text, "이익을")) %>% select(score) ``` ``` ## # A tibble: 11 x 1 ## score ## <dbl> ## 1 4 ## 2 3 ## 3 3 ## 4 2 ## 5 2 ## 6 2 ## 7 2 ## 8 1 ## 9 1 ## 10 1 ## 11 1 ``` ] .pull-right[ ```r # "이익을" 언급하지 않은 트윗 pos_jae %>% filter( !str_detect(text, "이익을")) %>% select(score) ``` ``` ## # A tibble: 712 x 1 ## score ## <dbl> ## 1 7 ## 2 6 ## 3 6 ## 4 6 ## 5 6 ## 6 5 ## 7 5 ## 8 5 ## 9 4 ## 10 4 ## # ... with 702 more rows ``` ] ] --- #### 부정 트윗 주요 단어 비교하기 ##### 1. 로그 오즈비 구하기 ```r # Wide form으로 변환 wide_neg <- frequency_sentiment %>% filter(sentiment == "부정" & !str_detect(word, "이낙연|이재명")) %>% pivot_wider(names_from = candidate, values_from = n, values_fill = list(n = 0)) # 로그 오즈비 구하기 log_odds_neg <- wide_neg %>% mutate(log_odds_ratio = log(((이낙연 + 1) / (sum(이낙연 + 1))) / ((이재명 + 1) / (sum(이재명 + 1))))) ``` --- ##### 2. 불용어 목록 만들기 ```r # 불용어 확인 log_odds_neg %>% group_by(candidate = ifelse(log_odds_ratio > 0, "이낙연", "이재명")) %>% slice_max(abs(log_odds_ratio), n = 15, with_ties = F) %>% select(word) ``` .scroll-box-20[ <pre class="r-output"><code>## Adding missing grouping variables: `candidate` </code></pre> ``` ## # A tibble: 30 x 2 ## # Groups: candidate [2] ## candidate word ## <chr> <chr> ## 1 이낙연 음성 ## 2 이낙연 의원님 ## 3 이낙연 총리님 ## 4 이낙연 자가격리 ## 5 이낙연 마이크 ## 6 이낙연 의원은 ## 7 이낙연 당대표 ## 8 이낙연 김종민 ## 9 이낙연 다행입니다 ## 10 이낙연 부디 ## 11 이낙연 의원을 ## 12 이낙연 김현정 ## 13 이낙연 당대표는 ## 14 이낙연 마이크를 ## 15 이낙연 무섭다 ## 16 이재명 경기도 *## 17 이재명 쓰나미급 *## 18 이재명 겪어보지 *## 19 이재명 지금껏 *## 20 이재명 대충격 ## 21 이재명 도지사 *## 22 이재명 시작될 ## 23 이재명 경기도가 ## 24 이재명 니가 ## 25 이재명 뭔지 ## 26 이재명 이유가 ## 27 이재명 경기도는 ## 28 이재명 그건 ## 29 이재명 새끼야 ## 30 이재명 주고 ``` ] --- - `"지금껏"`, `"겪어보지"`, `"쓰나미급"` - 코로나19 관련 기자 회견에서 "지금껏 겪어보지 못한 쓰나미급 대충격 시작될 것"이라고 표현한 일이 트위터에서 회자됨 ```r tweet %>% filter(candidate == "이재명") %>% find_word(x = text, keyword = "쓰나미급") ``` <pre class="r-output"><code>## [1] 이재명 "지금껏 겪어보지 못한 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 대충격 시작될 것" ㅎㅎ 붕신 그걸 누가 몰라?<br>##<br>## [2] 이재명 "지금껏 겪어보지 못한 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 대충격 시작될 것" 이 넘아 그걸 막아낼려는게 우리 정부와 방역당국, 지자체장들인데(경기도 빼고) 야당질 평론질하고있냐<br>##<br>## [3] 대통령은 엄중한 시기지만 지금까지 그래왔듯 할 수 있다고 국민들에게 희망과 용기를 주는데 이재명은 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 하면서 불안감만 조성하고 있다. </span></code></pre> --- - 불용어 목록 만들기 - 같은 문장에서 나온 단어들이므로 `"쓰나미급"`만 남겨두기 - 의미 파악 어려운 단어 불용어 처리 ```r # 불용어 목록 생성 stopword_neg <- c("지금껏", "겪어보지", "대충격", "시작될", "그건", "주고") ``` --- <br-back-20> ##### 3. 막대 그래프 만들기 ```r # 로그 오즈비 상하위 10개 단어 추출 top10_neg <- log_odds_neg %>% filter(!word %in% stopword_neg) %>% group_by(candidate = ifelse(log_odds_ratio > 0, "이낙연", "이재명")) %>% slice_max(abs(log_odds_ratio), n = 10, with_ties = F) # 막대 그래프 생성 ggplot(top10_neg, aes(x = reorder(word, log_odds_ratio), y = log_odds_ratio, fill = candidate)) + geom_col() + coord_flip() + scale_fill_manual(values = col_candidate) + labs(title = "차기 대선주자 부정 트윗 주요 단어", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, fill = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12)) ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-86-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 4. 롤리팝 차트 만들기(1/2) ```r # 단어 순서 지정해 factor 타입으로 변환 top10_neg <- top10_neg %>% ungroup() %>% mutate(word = reorder(word, log_odds_ratio)) # 롤리팝 차트 생성 ggplot(top10_neg, aes(x = word, y = log_odds_ratio, col = candidate)) + geom_segment(aes(x = word, xend = word, y = 0, yend = log_odds_ratio), size = 1.1) + geom_point(size = 3.5) + coord_flip() + scale_color_manual(values = col_candidate) + ``` --- ##### 4. 롤리팝 차트 만들기(2/2) ```r labs(title = "차기 대선주자 부정 트윗 주요 단어", subtitle = "2020.8.13 ~ 2020.8.21", x = NULL, y = NULL, col = NULL) + theme_minimal(12) + theme(text = element_text(family = "nanumgothic"), plot.title = element_text(size = 14, face = "bold"), plot.subtitle = element_text(size = 12)) ``` --- <img src="08-project2_files/figure-html/unnamed-chunk-89-1.png" width="70%" style="display: block; margin: auto;" /> --- ##### 5. 원문 살펴보기 ##### 5.1 이낙연 의원 부정 트윗 ```r # 이낙연 의원 부정 트윗 추출 neg_nak <- tweet %>% filter(sentiment == "부정" & candidate == "이낙연") %>% arrange(-score) ``` --- - **"음성"** : 이낙연 의원이 코로나19 확진 판정을 받을까봐 걱정하며 안타까운 심정을 표현한 내용 ```r neg_nak %>% find_word(x = text, keyword = "음성") ``` <pre class="r-output"><code>## [1] 정보의 최일선에 있는 기자들이 이런 엄청난 실수(?)를 저지르다니... 누구를 위한 고의가 아니었길 바라며 아울러 이낙연 후보님의 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span> 판정을 기원합니다!!<br>##<br>## [2] 이낙연의원님 확진자가 쓴 의자와 마이크를 써서 자가격리들어가셨다고. 부디 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span>이기를.._()_ i♡ny<br>##<br>## [3] 이낙연의원님의 코로나검사결과 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>음성</span><span>이길 간절히 바랍니다. 잠을 못잤습니다ㅜㅜ </span></code></pre> --- - **"의원님"** : 이낙연 의원의 정치 활동을 방해하는 일을 비판하는 내용 ```r neg_nak %>% find_word(x = text, keyword = "의원님") ``` <pre class="r-output"><code>## [1] 당대표는 이낙연<span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>이 틀림 없다 싶으니까 이젠 당 지지율을 끌어내리려고 발악을 하는구나!!!<br>##<br>## [2] 난 이낙연 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>의 안정성과 믿음이 그만큼 선명성 부족에서도 기인한다고 보고 동교동계와의 연결고리도 탐탁치가 않음 이낙연 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>께 제 2의 문프의 기대하는건 성급한 욕심일까 싶기도 함 그렇다해도 호시탐탐 문프의 빈틈을 노리는 듯한 이재명 보다는 나음 아 정치 모르겠다<br>##<br>## [3] 이낙연 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>의원님</span><span>, 말도 꺼내기 싫은 그 방송 출연 결정은 마치 '당 내 일부에 대한 극단적인 충성 성향'을 가진 '극렬 지지자'에게 구애한다는 의미에서, 래통당이 태극기 들고 시위하는 극우계의 '과대표된 목소리에 경도되는 선택'을 하는 것과 비슷하게 보입니다. </span></code></pre> --- ##### 5.2 이재명 경기도지사 부정 트윗 ```r # 이재명 경기도지사 부정 트윗 추출 neg_jae <- tweet %>% filter(sentiment == "부정" & candidate == "이재명") %>% arrange(-score) ``` --- - **"경기도"** : 이재명 경기도지사의 경기도 행정을 비판하는 내용 ```r neg_jae %>% find_word(x = text, keyword = "경기도") ``` <pre class="r-output"><code>## [1] 무식저질천박못생 오렌지 정똥찌끄레기 인간말종 전과4범 범죄자 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>랄지사 #점베 이재명 궤멸<br>##<br>## [2] </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span> 1인당 홍보비 1,871원 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span> 1인당 수해지원비 200원 이재명은 합니다~! 새로운 경기, 이제, 이재명! <펌> 폐악질 미친 이재명 경계해야 할 적폐기생충 기회주의자 조폭의혹 일베출신토설<br>##<br>## [3] 민주당 지지율이 그렇게 걱정이 되었다면 이재명은 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>경기도</span><span>지사 경선부터 나오지 말았어야지! 의견이다. </span></code></pre> --- - **"쓰나미급"** : "지금껏 겪어보지 못한 쓰나미급 대충격 시작될 것"이라고 표현한 일을 비판하는 내용 ```r neg_jae %>% find_word(x = text, keyword = "쓰나미급") ``` <pre class="r-output"><code>## [1] 이재명 "지금껏 겪어보지 못한 <span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 대충격 시작될 것" 이 넘아 그걸 막아낼려는게 우리 정부와 방역당국, 지자체장들인데(경기도 빼고) 야당질 평론질하고있냐<br>##<br>## [2] 이재명 "지금껏 겪어보지 못한 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 대충격 시작될 것" - 재난지원금 타령하려고? 이 도른새끼는 모든 게 조폭과 상품권으로 귀착된다.<br>##<br>## [3] 이재명 "지금껏 겪어보지 못한 </span><span style='color: #FFFFFF;background-color: #FF00AF;font-weight: bold;'>쓰나미급</span><span> 대충격 시작될 것" - 주둥이가 쌩양아치인 오랄리! </span></code></pre> --- class: title1 끝