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" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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 03 비교 분석: 무엇이 다를까? --- class: title0-2 We'll make <br-back-20> <img src="Image/03/03_3_1.png" width="70%" height="70%" /> --- class: title0-2 and <br-back-40> <img src="Image/03/03_4_1.png" width="70%" height="70%" /> --- <br> .large2[.font-jua[목차]] .large[.font-jua[03-1 단어 빈도 비교하기]]([link](#03-1)) .large[.font-jua[03-2 오즈비 - 상대적으로 중요한 단어 비교하기]]([link](#03-2)) .large[.font-jua[03-3 로그 오즈비로 단어 비교하기]]([link](#03-3)) .large[.font-jua[03-4 TF-IDF - 여러 텍스트의 단어 비교하기]]([link](#03-4)) --- name: 03-1 class: title1 03-1 단어 빈도 비교하기 --- ### 비교 분석 - 여러 텍스트를 비교해 차이를 알아보는 분석 방법 - 단어 빈도 분석을 응용해 자주 사용된 단어의 차이를 살펴봄 --- ### 텍스트 합치기 - 텍스트를 비교하기 위해 여러 개의 텍스트를 하나의 데이터셋으로 합치는 작업 ##### 데이터 불러오기 - 문재인 대통령과 박근혜 전 대통령의 대선 출마 선언문 불러오기 - tibble 구조로 변환하고 연설문 구분 위해 대통령 이름 부여 ```r library(dplyr) # 문재인 대통령 연설문 불러오기 raw_moon <- readLines("speech_moon.txt", encoding = "UTF-8") moon <- raw_moon %>% as_tibble() %>% mutate(president = "moon") # 박근혜 대통령 연설문 불러오기 raw_park <- readLines("speech_park.txt", encoding = "UTF-8") park <- raw_park %>% as_tibble() %>% mutate(president = "park") ``` --- ##### 데이터 합치기 - 두 데이터를 행(세로) 방향으로 결합 - 출력 결과 보기 편하게 `select()`로 변수 순서 바꾸기 - 윗부분은 문재인 대통령, 아랫부분은 박근혜 전 대통령 연설문 ```r bind_speeches <- bind_rows(moon, park) %>% select(president, value) ``` -- <br-back-30> .pull-left[ ```r head(bind_speeches) ``` ``` ## # A tibble: 6 x 2 ## president value ## <chr> <chr> ## 1 moon "정권교체 하~ ## 2 moon " 정치교체 ~ ## 3 moon " 시대교체 ~ ## 4 moon " " ## 5 moon " ‘불비불~ ## 6 moon "" ``` ] .pull-right[ ```r tail(bind_speeches) ``` ``` ## # A tibble: 6 x 2 ## president value ## <chr> <chr> ## 1 park "국민들이 꿈~ ## 2 park "" ## 3 park "감사합니다." ## 4 park "" ## 5 park "2012년 7월 ~ ## 6 park "새누리당 예~ ``` ] <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> 박근혜 전 대통령의 대선 출마 선언문 출처: [bit.ly/easytext_31](https://bit.ly/easytext_31) --- #### 집단별 단어 빈도 구하기 ##### 1. 기본적인 전처리 및 토큰화 - 한글 이외의 문자, 연속된 공백 제거 - `bind_speeches`는 tibble 구조이므로 `mutate()` 활용 ```r # 기본적인 전처리 library(stringr) speeches <- bind_speeches %>% mutate(value = str_replace_all(value, "[^가-힣]", " "), value = str_squish(value)) speeches ``` --- ``` ## # A tibble: 213 x 2 ## president value ## <chr> <chr> ## 1 moon "정권교체 하겠습니다" ## 2 moon "정치교체 하겠습니다" ## 3 moon "시대교체 하겠습니다" ## 4 moon "" ## 5 moon "불비불명 이라는 고사가 있습니다 남~ ## 6 moon "" ## 7 moon "그 동안 정치와 거리를 둬 왔습니다 ~ ## 8 moon "" ## 9 moon "" ## 10 moon "우리나라 대통령 이 되겠습니다" ## # ... with 203 more rows ``` --- - 형태소 분석기를 이용해 명사 기준 토큰화 ```r # 토큰화 library(tidytext) library(KoNLP) speeches <- speeches %>% unnest_tokens(input = value, output = word, token = extractNoun) speeches ``` --- ``` ## # A tibble: 2,997 x 2 ## president word ## <chr> <chr> ## 1 moon "정권교체" ## 2 moon "하겠습니" ## 3 moon "정치" ## 4 moon "교체" ## 5 moon "하겠습니" ## 6 moon "시대" ## 7 moon "교체" ## 8 moon "하겠습니" ## 9 moon "" ## 10 moon "불비불명" ## # ... with 2,987 more rows ``` --- #### 하위 집단별 단어 빈도 구하기 - `count()` - `"moon"`과 `"park"`의 단어 빈도 각각 구하기 ##### 샘플 텍스트로 작동 원리 알아보기 - `count()`에 집단을 구성하는 두 변수를 순서대로 입력 ```r df <- tibble(class = c("a", "a", "a", "b", "b", "b"), sex = c("female", "male", "female", "male", "male", "female")) ``` .pull-left[ ```r df ``` ``` ## # A tibble: 6 x 2 ## class sex ## <chr> <chr> ## 1 a female ## 2 a male ## 3 a female ## 4 b male ## 5 b male ## 6 b female ``` ] .pull-right[ ```r df %>% count(class, sex) ``` ``` ## # A tibble: 4 x 3 ## class sex n ## <chr> <chr> <int> ## 1 a female 2 ## 2 a male 1 ## 3 b female 1 ## 4 b male 2 ``` ] --- ##### 두 연설문의 단어 빈도 구하기 ```r frequency <- speeches %>% count(president, word) %>% # 연설문 및 단어별 빈도 filter(str_count(word) > 1) # 두 글자 이상 추출 head(frequency) ``` ``` ## # A tibble: 6 x 3 ## president word n ## <chr> <chr> <int> ## 1 moon 가동 1 ## 2 moon 가사 1 ## 3 moon 가슴 2 ## 4 moon 가족 1 ## 5 moon 가족구조 1 ## 6 moon 가지 4 ``` <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> `count()`는 입력한 변수의 알파벳, 가나다순으로 행을 정렬함 --- #### 자주 사용된 단어 추출하기 - `dplyr::slice_max()`: 값이 큰 상위 n개의 행을 추출해 내림차순 정렬 ##### 샘플 데이터로 작동 원리 알아보기 ```r df <- tibble(x = c(1:100)) ``` <br-back-20> .pull-left[ ```r df ``` ``` ## # A tibble: 100 x 1 ## x ## <int> ## 1 1 ## 2 2 ## 3 3 ## 4 4 ## 5 5 ## 6 6 ## 7 7 ## 8 8 ## 9 9 ## 10 10 ## # ... with 90 more rows ``` ] .pull-right[ ```r df %>% slice_max(x, n = 3) ``` ``` ## # A tibble: 3 x 1 ## x ## <int> ## 1 100 ## 2 99 ## 3 98 ``` ] --- .pull-left[ <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> `slice_min()`: 값이 작은 하위 n개 추출 ```r df %>% slice_min(x, n = 3) ``` ``` ## # A tibble: 3 x 1 ## x ## <int> ## 1 1 ## 2 2 ## 3 3 ``` ] --- #### 연설문에 가장 많이 사용된 단어 추출하기 - `president`별 고빈도 단어 상위 10개 추출 ```r top10 <- frequency %>% group_by(president) %>% # president별로 분리 slice_max(n, n = 10) # 상위 10개 추출 top10 ``` --- ``` ## # A tibble: 22 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 일자리 21 ## 3 moon 나라 19 ## 4 moon 우리 17 ## 5 moon 경제 15 ## 6 moon 사회 14 ## 7 moon 성장 13 ## 8 moon 대통령 12 ## 9 moon 정치 12 ## 10 moon 하게 12 ## 11 park 국민 72 ## 12 park 행복 23 ## 13 park 여러분 20 ## 14 park 정부 17 ## 15 park 경제 15 ## 16 park 신뢰 11 ## 17 park 국가 10 ## 18 park 우리 10 ## 19 park 교육 9 ## 20 park 사람 9 ## 21 park 사회 9 ## 22 park 일자리 9 ``` --- #### 단어 빈도 동점 처리 - 두 연설문에서 단어 10개씩 추출했는데 20행이 아니라 22행 - 단어 빈도 동점인 행이 전부 추출되었기 때문 ```r top10 ``` ``` *## # A tibble: 22 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 일자리 21 ## 3 moon 나라 19 ## 4 moon 우리 17 ## 5 moon 경제 15 ## 6 moon 사회 14 ## 7 moon 성장 13 ## 8 moon 대통령 12 ## 9 moon 정치 12 ## 10 moon 하게 12 ## # ... with 12 more rows ``` --- - 박근혜 전 대통령의 연설문 단어 12개 - `"교육"`, `"사람"`, `"사회"`, `"일자리"` 빈도 동점, 모두 추출되면서 행 늘어남 ```r top10 %>% filter(president == "park") ``` ``` ## # A tibble: 12 x 3 ## # Groups: president [1] ## president word n ## <chr> <chr> <int> ## 1 park 국민 72 ## 2 park 행복 23 ## 3 park 여러분 20 ## 4 park 정부 17 ## 5 park 경제 15 ## 6 park 신뢰 11 ## 7 park 국가 10 ## 8 park 우리 10 *## 9 park 교육 9 *## 10 park 사람 9 *## 11 park 사회 9 *## 12 park 일자리 9 ``` --- #### 빈도 동점 단어 제외하고 추출하기 - `slice_max(with_ties = F)`: 원본 데이터의 정렬 순서에 따라 행 추출 ##### 샘플 데이터로 작동 원리 알아보기 ```r df <- tibble(x = c("A", "B", "C", "D"), y = c(4, 3, 2, 2)) ``` <br-back-20> .pull-left[ ```r df %>% slice_max(y, n = 3) ``` ``` ## # A tibble: 4 x 2 ## x y ## <chr> <dbl> ## 1 A 4 ## 2 B 3 ## 3 C 2 ## 4 D 2 ``` ] .pull-right[ ```r df %>% slice_max(y, n = 3, with_ties = F) ``` ``` ## # A tibble: 3 x 2 ## x y ## <chr> <dbl> ## 1 A 4 ## 2 B 3 ## 3 C 2 ``` ] --- #### 연설문에 적용하기 ```r top10 <- frequency %>% group_by(president) %>% slice_max(n, n = 10, with_ties = F) top10 ``` --- ``` *## # A tibble: 20 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 일자리 21 ## 3 moon 나라 19 ## 4 moon 우리 17 ## 5 moon 경제 15 ## 6 moon 사회 14 ## 7 moon 성장 13 ## 8 moon 대통령 12 ## 9 moon 정치 12 ## 10 moon 하게 12 ## 11 park 국민 72 ## 12 park 행복 23 ## 13 park 여러분 20 ## 14 park 정부 17 ## 15 park 경제 15 ## 16 park 신뢰 11 ## 17 park 국가 10 ## 18 park 우리 10 ## 19 park 교육 9 ## 20 park 사람 9 ``` --- #### 막대 그래프 만들기 ##### 1. 변수의 항목별로 그래프만들기 - `facet_wrap()` - `~` 뒤에 그래프를 나누는 기준 변수 입력 ```r library(ggplot2) ggplot(top10, aes(x = reorder(word, n), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president) ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-32-1.png" width="100%" /> --- ##### 2. 그래프별 y축 설정하기 - 축을 구성하는 단어가 한 범주에만 있으면 축은 있지만 막대는 없는 항목 생김 - ex) `"행복"`, `"나라"` <img src="03-comparing_files/figure-html/unnamed-chunk-34-1.png" width="90%" /> --- ##### 2. 그래프별 y축 설정하기 - 축을 구성하는 단어가 한 범주에만 있으면 축은 있지만 막대는 없는 항목 생김 - ex) `"행복"`, `"나라"` - `scales`: 그래프의 축 통일 또는 각각 생성 결정 - `"fixed"`: 축 통일(기본값) - `"free_y"`: 범주별로 y축 만듦 ```r ggplot(top10, aes(x = reorder(word, n), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president, # president별 그래프 생성 * scales = "free_y") # y축 통일하지 않음 ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-36-1.png" width="100%" /> --- #### 3. 특정 단어 제외하고 막대 그래프 만들기 - 박근혜 전 대통령 `"국민"` 빈도 너무 높아 다른 단어들 차이 드러나지 않음 <img src="03-comparing_files/figure-html/unnamed-chunk-37-1.png" width="80%" /> --- #### 3. 특정 단어 제외하고 막대 그래프 만들기 - 박근혜 전 대통령 `"국민"` 빈도 너무 높아 다른 단어들 차이 드러나지 않음 - 전반적인 단어 빈도가 잘 드러나도록 제거 ```r top10 <- frequency %>% filter(word != "국민") %>% group_by(president) %>% slice_max(n, n = 10, with_ties = F) ``` -- ```r ggplot(top10, aes(x = reorder(word, n), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president, scales = "free_y") ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-40-1.png" width="100%" /> --- #### 4. 축 정렬하기 - x축을 지정할 때 `reorder()`를 사용했는데도 막대가 빈도 기준으로 완벽하게 정렬되지 않음 - 전체 빈도 기준으로 각 범주의 x축 순서를 정했기 때문 <img src="03-comparing_files/figure-html/unnamed-chunk-41-1.png" width="80%" /> --- #### 4. 축 정렬하기 - x축을 지정할 때 `reorder()`를 사용했는데도 막대가 빈도 기준으로 완벽하게 정렬되지 않음 - 전체 빈도 기준으로 각 범주의 x축 순서를 정했기 때문 ##### 그래프별로 축 정렬하기 - `tidytext::reorder_within()`: 변수의 항목별로 축 순서 따로 구하기 - `x` : 축 - `by` :정렬 기준 - `within` : 그래프를 나누는 기준 ```r ggplot(top10, aes(x = reorder_within(word, n, president), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president, scales = "free_y") ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-43-1.png" width="100%" /> --- #### 5. 변수 항목 제거하기 - `tidytext::scale_x_reordered()`: 각 단어 뒤의 범주 항목 제거 ```r ggplot(top10, aes(x = reorder_within(word, n, president), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president, scales = "free_y") + * scale_x_reordered() + labs(x = NULL) + # x축 삭제 theme(text = element_text(family = "nanumgothic")) # 폰트 ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-45-1.png" width="100%" /> --- name: 03-2 class: title1 03-2 오즈비: <br> 상대적으로 중요한 단어 비교하기 --- - 빈도 높은 단어를 비교하면 - 어떤 텍스트든 일반적인 단어 빈도 높아 텍스트 차이 잘 드러나지 않음 - ex) 연설문: `"우리"`, `"사회"`, `"경제"`, `"일자리"` -- - 텍스트의 차이를 알아보려면 - 특정 텍스트에는 많이 사용되었지만 다른 텍스트에는 적게 사용된 단어를 살펴봐야함 --- #### Long form을 Wide form으로 변환하기 - 여러 텍스트 비교하기 편하게 데이터 구조 바꾸기 -- ##### Long form 데이터 살펴보기 - `frequency`: `president`가 `"moon"`인 행과 `"park"`인 행이 세로로 길게 나열 ```r df_long <- frequency %>% group_by(president) %>% slice_max(n, n = 10) %>% filter(word %in% c("국민", "우리", "정치", "행복")) df_long ``` <br-back-10> ``` ## # A tibble: 6 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 우리 17 ## 3 moon 정치 12 ## 4 park 국민 72 ## 5 park 행복 23 ## 6 park 우리 10 ``` --- ##### Long form 데이터 - 같은 단어가 범주별로 다른 행을 구성 - 범주별 빈도 비교 어려움 - 빈도를 활용해 연산하기 불편 ``` ## # A tibble: 6 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 우리 17 ## 3 moon 정치 12 ## 4 park 국민 72 ## 5 park 행복 23 ## 6 park 우리 10 ``` --- ##### Long form을 Wide form으로 변형하기 - **wide form**: 가로로 넓은 형태의 데이터 - 범주별로 단어 빈도 비교하기 편함 - 변수간 연산하기 편함 .pull-left[ ```r df_long ``` ``` ## # A tibble: 6 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 우리 17 ## 3 moon 정치 12 ## 4 park 국민 72 ## 5 park 행복 23 ## 6 park 우리 10 ``` ] .pull-right[ ```r df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 0 ## 4 행복 0 23 ``` ] --- - `tidyr::pivot_wider()`: long form을 wide form으로 변환 - `names_from`: 변수명으로 만들 값이 들어 있는 변수 - `values_from`: 변수에 채워넣을 값이 들어 있는 변수 ```r install.packages("tidyr") library(tidyr) df_wide <- df_long %>% pivot_wider(names_from = president, values_from = n) df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 NA ## 4 행복 NA 23 ``` --- ##### Wide form - 한 단어가 한 행으로 구성됨 - 범주별 단어 빈도 비교하기 쉬움 ```r df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 NA ## 4 행복 NA 23 ``` --- .pull-left[ ```r df_long ``` ``` ## # A tibble: 6 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 우리 17 ## 3 moon 정치 12 ## 4 park 국민 72 ## 5 park 행복 23 ## 6 park 우리 10 ``` ] .pull-right[ ```r df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 NA ## 4 행복 NA 23 ``` ] --- ##### `NA`를 `0`으로 바꾸기 - 어떤 단어가 둘 중 한 범주에만 있으면 `NA` - 오즈비 계산하기 위해 `0`으로 변환해야 함 ```r df_wide <- df_long %>% pivot_wider(names_from = president, values_from = n, * values_fill = list(n = 0)) df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 0 ## 4 행복 0 23 ``` --- .pull-left[ ```r df_long ``` ``` ## # A tibble: 6 x 3 ## # Groups: president [2] ## president word n ## <chr> <chr> <int> ## 1 moon 국민 21 ## 2 moon 우리 17 ## 3 moon 정치 12 ## 4 park 국민 72 ## 5 park 행복 23 ## 6 park 우리 10 ``` ] .pull-right[ ```r df_wide ``` ``` ## # A tibble: 4 x 3 ## word moon park ## <chr> <int> <int> ## 1 국민 21 72 ## 2 우리 17 10 ## 3 정치 12 0 ## 4 행복 0 23 ``` ] --- ##### 연설문 단어 빈도를 Wide form으로 변환하기 ```r frequency_wide <- frequency %>% pivot_wider(names_from = president, values_from = n, values_fill = list(n = 0)) frequency_wide ``` ``` ## # A tibble: 955 x 3 ## word moon park ## <chr> <int> <int> ## 1 가동 1 0 ## 2 가사 1 0 ## 3 가슴 2 0 ## 4 가족 1 1 ## 5 가족구조 1 0 ## 6 가지 4 0 ## 7 가치 3 1 ## 8 각종 1 0 ## 9 감당 1 0 ## 10 강력 3 0 ## # ... with 945 more rows ``` --- #### 오즈비 구하기 - **오즈비(odds ratio)** - 어떤 사건이 A 조건에서 발생할 확률이 B 조건에서 발생할 확률에 비해 얼마나 더 큰지를 나타냄 - 단어가 두 텍스트 중 어디에 등장할 확률이 높은지, 상대적인 중요도를 알 수 있음 -- <br> .pull-left[ `$${\large\text{odds ratio} = \frac{\left(\frac{n+1}{\text{total}+1}\right)_\text{Text A}} {\left(\frac{n+1}{\text{total}+1}\right)_\text{Text B}}}$$` - `\(n\)`: 각 단어의 빈도 - `\(\text{total}\)`: 전체 단어 빈도 ] --- ##### 1. 단어의 비중을 나타낸 변수 추가하기 - 각 단어가 두 연설문에서 차지하는 비중을 나타낸 변수 - 연설문별로 '각 단어의 빈도'를 '모든 단어 빈도의 합'으로 나눔 ```r frequency_wide <- frequency_wide %>% mutate(ratio_moon = ((moon)/(sum(moon))), # moon 에서 단어의 비중 ratio_park = ((park)/(sum(park)))) # park 에서 단어의 비중 frequency_wide ``` ``` ## # A tibble: 955 x 5 ## word moon park ratio_moon ratio_park ## <chr> <int> <int> <dbl> <dbl> ## 1 가동 1 0 0.000749 0 ## 2 가사 1 0 0.000749 0 ## 3 가슴 2 0 0.00150 0 ## 4 가족 1 1 0.000749 0.00117 ## 5 가족구조 1 0 0.000749 0 ## 6 가지 4 0 0.00299 0 ## 7 가치 3 1 0.00225 0.00117 ## 8 각종 1 0 0.000749 0 ## 9 감당 1 0 0.000749 0 ## 10 강력 3 0 0.00225 0 ## # ... with 945 more rows ``` --- ##### 1. 단어의 비중을 나타낸 변수 추가하기 - 어떤 단어가 한 연설문에 전혀 사용되지 않으면 빈도 0, 오즈비 0, 단어 비중 비교 불가 - 빈도가 0보다 큰 값이 되도록 모든 값에 `+1` ```r frequency_wide <- frequency_wide %>% mutate(ratio_moon = ((moon + 1)/(sum(moon + 1))), # moon에서 단어의 비중 ratio_park = ((park + 1)/(sum(park + 1)))) # park에서 단어의 비중 frequency_wide ``` ``` ## # A tibble: 955 x 5 ## word moon park ratio_moon ratio_park ## <chr> <int> <int> <dbl> <dbl> ## 1 가동 1 0 0.000873 0.000552 ## 2 가사 1 0 0.000873 0.000552 ## 3 가슴 2 0 0.00131 0.000552 ## 4 가족 1 1 0.000873 0.00110 ## 5 가족구조 1 0 0.000873 0.000552 ## 6 가지 4 0 0.00218 0.000552 ## 7 가치 3 1 0.00175 0.00110 ## 8 각종 1 0 0.000873 0.000552 ## 9 감당 1 0 0.000873 0.000552 ## 10 강력 3 0 0.00175 0.000552 ## # ... with 945 more rows ``` --- #### 2. 오즈비 변수 추가하기 - 한 텍스트의 단어 비중을 다른 텍스트의 단어 비중으로 나눔 ```r frequency_wide <- frequency_wide %>% mutate(odds_ratio = ratio_moon/ratio_park) frequency_wide ``` ``` ## # A tibble: 955 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 가동 1 0 0.000873 0.000552 1.58 ## 2 가사 1 0 0.000873 0.000552 1.58 ## 3 가슴 2 0 0.00131 0.000552 2.37 ## 4 가족 1 1 0.000873 0.00110 0.791 ## 5 가족구조 1 0 0.000873 0.000552 1.58 ## 6 가지 4 0 0.00218 0.000552 3.96 ## 7 가치 3 1 0.00175 0.00110 1.58 ## 8 각종 1 0 0.000873 0.000552 1.58 ## 9 감당 1 0 0.000873 0.000552 1.58 ## 10 강력 3 0 0.00175 0.000552 3.17 ## # ... with 945 more rows ``` --- - 오즈비를 보면 단어가 어떤 텍스트에서 상대적으로 더 많이 사용됐는지 알 수 있음 - **`"moon"`에서 상대적인 비중 클수록 1보다 큰 값** - `"park"`에서 상대적인 비중 클수록 1보다 작은 값 - 두 연설문에서 단어 비중 같으면 1 ```r frequency_wide %>% * arrange(-odds_ratio) ``` ``` ## # A tibble: 955 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 복지국가 8 0 0.00393 0.000552 7.12 ## 2 세상 6 0 0.00306 0.000552 5.54 ## 3 여성 6 0 0.00306 0.000552 5.54 ## 4 정의 6 0 0.00306 0.000552 5.54 ## 5 강자 5 0 0.00262 0.000552 4.75 ## 6 공평 5 0 0.00262 0.000552 4.75 ## 7 대통령의 5 0 0.00262 0.000552 4.75 ## 8 보통 5 0 0.00262 0.000552 4.75 ## 9 상생 5 0 0.00262 0.000552 4.75 ## 10 지방 5 0 0.00262 0.000552 4.75 ## # ... with 945 more rows ``` --- - 오즈비를 보면 단어가 어떤 텍스트에서 상대적으로 더 많이 사용됐는지 알 수 있음 - `"moon"`에서 상대적인 비중 클수록 1보다 큰 값 - **`"park"`에서 상대적인 비중 클수록 1보다 작은 값** - 두 연설문에서 단어 비중 같으면 1 ```r frequency_wide %>% * arrange(odds_ratio) ``` ``` ## # A tibble: 955 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 박근혜 0 8 0.000436 0.00496 0.0879 ## 2 여러분 2 20 0.00131 0.0116 0.113 ## 3 행복 3 23 0.00175 0.0132 0.132 ## 4 실천 0 5 0.000436 0.00331 0.132 ## 5 정보 0 5 0.000436 0.00331 0.132 ## 6 투명 0 5 0.000436 0.00331 0.132 ## 7 과제 0 4 0.000436 0.00276 0.158 ## 8 국정운영 0 4 0.000436 0.00276 0.158 ## 9 시작 0 4 0.000436 0.00276 0.158 ## 10 지식 0 4 0.000436 0.00276 0.158 ## # ... with 945 more rows ``` --- - 오즈비를 보면 단어가 어떤 텍스트에서 상대적으로 더 많이 사용됐는지 알 수 있음 - `"moon"`에서 상대적인 비중 클수록 1보다 큰 값 - `"park"`에서 상대적인 비중 클수록 1보다 작은 값 - **두 연설문에서 단어 비중 같으면 1** ```r frequency_wide %>% * arrange(abs(1 - odds_ratio)) ``` ``` ## # A tibble: 955 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 때문 4 3 0.00218 0.00221 0.989 ## 2 강화 3 2 0.00175 0.00165 1.06 ## 3 부담 3 2 0.00175 0.00165 1.06 ## 4 세계 3 2 0.00175 0.00165 1.06 ## 5 책임 3 2 0.00175 0.00165 1.06 ## 6 협력 3 2 0.00175 0.00165 1.06 ## 7 거대 2 1 0.00131 0.00110 1.19 ## 8 교체 2 1 0.00131 0.00110 1.19 ## 9 근본적 2 1 0.00131 0.00110 1.19 ## 10 기반 2 1 0.00131 0.00110 1.19 ## # ... with 945 more rows ``` --- .box[ .info[<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FF7333;" xmlns="http://www.w3.org/2000/svg"> <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> 오즈비 간단히 구하기] ```r frequency_wide <- frequency_wide %>% mutate(odds_ratio = ((moon + 1)/(sum(moon + 1)))/ ((park + 1)/(sum(park + 1)))) ``` ] --- #### 상대적으로 중요한 단어 추출하기 ##### 오즈비가 가장 높거나 가장 낮은 단어 추출하기 --- #### 순위 구하기 - `rank()` ##### 샘플 데이터로 작동 원리 알아보기 ```r df <- tibble(x = c(2, 5, 10)) df ``` ``` ## # A tibble: 3 x 1 ## x ## <dbl> ## 1 2 ## 2 5 ## 3 10 ``` <br-back-10> .pull-left[ ```r # 값이 작을수록 앞순위 df %>% mutate(y = rank(x)) ``` ``` ## # A tibble: 3 x 2 ## x y ## <dbl> <dbl> ## 1 2 1 ## 2 5 2 ## 3 10 3 ``` ] .pull-right[ ```r # 값이 클수록 앞순위 df %>% mutate(y = rank(-x)) ``` ``` ## # A tibble: 3 x 2 ## x y ## <dbl> <dbl> ## 1 2 3 ## 2 5 2 ## 3 10 1 ``` ] --- #### 상대적으로 중요한 단어 추출하기 ##### 오즈비가 가장 높거나 가장 낮은 단어 추출하기 ```r top10 <- frequency_wide %>% filter(rank(odds_ratio) <= 10 | rank(-odds_ratio) <= 10) ``` -- ```r top10 %>% arrange(-odds_ratio) ``` --- - 상위 10개: `"moon"`에서 더 자주 사용되어 `odds_ratio`가 높은 단어 ``` ## # A tibble: 20 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> *## 1 복지국가 8 0 0.00393 0.000552 7.12 *## 2 세상 6 0 0.00306 0.000552 5.54 *## 3 여성 6 0 0.00306 0.000552 5.54 *## 4 정의 6 0 0.00306 0.000552 5.54 *## 5 강자 5 0 0.00262 0.000552 4.75 *## 6 공평 5 0 0.00262 0.000552 4.75 *## 7 대통령의 5 0 0.00262 0.000552 4.75 *## 8 보통 5 0 0.00262 0.000552 4.75 *## 9 상생 5 0 0.00262 0.000552 4.75 *## 10 지방 5 0 0.00262 0.000552 4.75 ## 11 과제 0 4 0.000436 0.00276 0.158 ## 12 국정운영 0 4 0.000436 0.00276 0.158 ## 13 시작 0 4 0.000436 0.00276 0.158 ## 14 지식 0 4 0.000436 0.00276 0.158 ## 15 행복 3 23 0.00175 0.0132 0.132 ## 16 실천 0 5 0.000436 0.00331 0.132 ## 17 정보 0 5 0.000436 0.00331 0.132 ## 18 투명 0 5 0.000436 0.00331 0.132 ## 19 여러분 2 20 0.00131 0.0116 0.113 ## 20 박근혜 0 8 0.000436 0.00496 0.0879 ``` --- - 하위 10개: `"park"`에서 더 자주 사용되어 `odds_ratio`가 낮은 단어 ``` ## # A tibble: 20 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 복지국가 8 0 0.00393 0.000552 7.12 ## 2 세상 6 0 0.00306 0.000552 5.54 ## 3 여성 6 0 0.00306 0.000552 5.54 ## 4 정의 6 0 0.00306 0.000552 5.54 ## 5 강자 5 0 0.00262 0.000552 4.75 ## 6 공평 5 0 0.00262 0.000552 4.75 ## 7 대통령의 5 0 0.00262 0.000552 4.75 ## 8 보통 5 0 0.00262 0.000552 4.75 ## 9 상생 5 0 0.00262 0.000552 4.75 ## 10 지방 5 0 0.00262 0.000552 4.75 *## 11 과제 0 4 0.000436 0.00276 0.158 *## 12 국정운영 0 4 0.000436 0.00276 0.158 *## 13 시작 0 4 0.000436 0.00276 0.158 *## 14 지식 0 4 0.000436 0.00276 0.158 *## 15 행복 3 23 0.00175 0.0132 0.132 *## 16 실천 0 5 0.000436 0.00331 0.132 *## 17 정보 0 5 0.000436 0.00331 0.132 *## 18 투명 0 5 0.000436 0.00331 0.132 *## 19 여러분 2 20 0.00131 0.0116 0.113 *## 20 박근혜 0 8 0.000436 0.00496 0.0879 ``` --- #### 막대 그래프 만들기 ##### 1. 비중이 큰 연설문을 나타낸 변수 추가하기 ```r top10 <- top10 %>% mutate(president = ifelse(odds_ratio > 1, "moon", "park"), n = ifelse(odds_ratio > 1, moon, park)) top10 ``` ``` ## # A tibble: 20 x 8 ## word moon park ratio_moon ratio_park odds_ratio president n ## <chr> <int> <int> <dbl> <dbl> <dbl> <chr> <int> ## 1 강자 5 0 0.00262 0.000552 4.75 moon 5 ## 2 공평 5 0 0.00262 0.000552 4.75 moon 5 ## 3 대통령의 5 0 0.00262 0.000552 4.75 moon 5 ## 4 보통 5 0 0.00262 0.000552 4.75 moon 5 ## 5 복지국가 8 0 0.00393 0.000552 7.12 moon 8 ## 6 상생 5 0 0.00262 0.000552 4.75 moon 5 ## 7 세상 6 0 0.00306 0.000552 5.54 moon 6 ## 8 여러분 2 20 0.00131 0.0116 0.113 park 20 ## 9 여성 6 0 0.00306 0.000552 5.54 moon 6 ## 10 정의 6 0 0.00306 0.000552 5.54 moon 6 ## # ... with 10 more rows ``` --- ##### 2. 막대 그래프 만들기 ```r ggplot(top10, aes(x = reorder_within(word, n, president), y = n, fill = president)) + geom_col() + coord_flip() + facet_wrap(~ president, scales = "free_y") + scale_x_reordered() ``` <img src="03-comparing_files/figure-html/unnamed-chunk-73-1.png" width="60%" /> --- - 전반적으로 "park"의 단어 빈도가 높아보임 - `"park"`의 `"행복"` 빈도 기준으로 두 그래프의 x축 크기를 똑같이 고정했기 때문 <img src="03-comparing_files/figure-html/unnamed-chunk-74-1.png" width="80%" /> --- ##### 3. 그래프별로 축 설정하기 - 범주별로 단어 비중 알 수 있도록 x축 크기 각각 정하기 ```r ggplot(top10, aes(x = reorder_within(word, n, president), y = n, fill = president)) + geom_col() + coord_flip() + * facet_wrap(~ president, scales = "free") + scale_x_reordered() + labs(x = NULL) + # x축 삭제 theme(text = element_text(family = "nanumgothic")) # 폰트 ``` <img src="03-comparing_files/figure-html/unnamed-chunk-75-1.png" width="40%" /> --- <svg viewBox="0 0 576 512" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FF7333;" xmlns="http://www.w3.org/2000/svg"> <path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg> **x축 크기가 그래프마다 다르므로 해석 조심** <br-back-10> - 막대 길이 같아도 단어 빈도 다름 - 두 텍스트 단어 빈도 비교 X - 각 텍스트에서 상대적으로 중요한 단어가 무엇인지 중심으로 해석 <img src="03-comparing_files/figure-html/unnamed-chunk-76-1.png" width="80%" /> --- #### 주요 단어가 사용된 문장 살펴보기 ##### 1. 원문을 문장 기준으로 토큰화하기 ```r speeches_sentence <- bind_speeches %>% as_tibble() %>% unnest_tokens(input = value, output = sentence, token = "sentences") speeches_sentence ``` ``` ## # A tibble: 329 x 2 ## president sentence ## <chr> <chr> ## 1 moon "정권교체 하겠습니다!" ## 2 moon "정치교체 하겠습니다!" ## 3 moon "시대교체 하겠습니다!" ## 4 moon "" ## 5 moon "‘불비불명(不飛不鳴)’이라는 고사가 있습니다." ## 6 moon "남쪽 언덕 나뭇가지에 앉아, 3년 동안 날지도 울지도 않는 새." ## 7 moon "그러나 그 새는 한번 날면 하늘 끝까지 날고, 한번 울면 천지를 뒤흔듭~ ## 8 moon "그 동안 정치와 거리를 둬 왔습니다." ## # ... with 321 more rows ``` --- ```r head(speeches_sentence) ``` ``` ## # A tibble: 6 x 2 ## president sentence ## <chr> <chr> ## 1 moon "정권교체 하겠습니다!" ## 2 moon "정치교체 하겠습니다!" ## 3 moon "시대교체 하겠습니다!" ## 4 moon "" ## 5 moon "‘불비불명(不飛不鳴)’이라는 고사가 있습니다." ## 6 moon "남쪽 언덕 나뭇가지에 앉아, 3년 동안 날지도 울지도 않는 새." ``` ```r tail(speeches_sentence) ``` ``` ## # A tibble: 6 x 2 ## president sentence ## <chr> <chr> ## 1 park 국민 여러분의 행복이 곧 저의 행복입니다. ## 2 park 사랑하는 조국 대한민국과 국민 여러분을 위해, 앞으로 머나 먼 길, 끝~ ## 3 park 그 길을 함께 해주시길 부탁드립니다. ## 4 park 감사합니다. ## 5 park 2012년 7월 10일 ## 6 park 새누리당 예비후보 박근혜 ``` --- #### 2. 주요 단어가 사용된 문장 추출하기 - `str_detect()` ```r speeches_sentence %>% filter(president == "moon" & str_detect(sentence, "복지국가")) ``` ``` ## # A tibble: 8 x 2 ## president sentence ## <chr> <chr> ## 1 moon ‘강한 복지국가’를 향해 담대하게 나아가겠습니다. ## 2 moon 2백 년 전 이와 같은 소득재분배, 복지국가의 사상을 가진 위정자가 지~ ## 3 moon 이제 우리는 복지국가를 향해 담대하게 나아갈 때입니다. ## 4 moon 부자감세, 4대강 사업 같은 시대착오적 과오를 청산하고, 하루빨리 복지~ ## 5 moon 우리는 지금 복지국가로 가느냐, 양극화의 분열된 국가로 가느냐 하는 ~ ## 6 moon 강한 복지국가일수록 국가 경쟁력도 더 높습니다. ## 7 moon 결국 복지국가로 가는 길은 사람에 대한 투자, 일자리 창출, 자영업 고~ ## 8 moon 우리는 과감히 강한 보편적 복지국가로 가야 합니다. ``` --- #### 2. 주요 단어가 사용된 문장 추출하기 - `str_detect()` ```r speeches_sentence %>% filter(president == "park" & str_detect(sentence, "행복")) ``` ``` ## # A tibble: 19 x 2 ## president sentence ## <chr> <chr> ## 1 park 저는 오늘, 국민 한 분 한 분의 꿈이 이루어지는 행복한 대한민국을 만~ ## 2 park 국가는 발전했고, 경제는 성장했다는데, 나의 삶은 나아지지 않았고, ~ ## 3 park 과거에는 국가의 발전이 국민의 행복으로 이어졌습니다. ## 4 park 개인의 창의력이 중요한 지식기반사회에서는 국민 한 사람, 한 사람이 ~ ## 5 park 이제 국정운영의 패러다임을 국가에서 국민으로, 개인의 삶과 행복 중~ ## 6 park 국민 개개인의 꿈을 향한 노력이 국가를 발전시키고 국가 발전이 국민 ~ ## 7 park 저는 ‘경제민주화 실현’, ‘일자리 창출’, 그리고 ‘한국형 복지의 ~ ## 8 park 국민행복의 길을 열어갈 첫 번째 과제로, 저는 경제민주화를 통해 중소~ ## 9 park 국민행복의 길을 열어갈 두 번째 과제로, 저는 좋은 일자리 창출을 통~ ## 10 park 국민행복의 길을 열어갈 세 번째 과제로, 우리의 실정에 맞으면서 국민~ ## # ... with 9 more rows ``` --- #### 중요도가 비슷한 단어 살펴보기 - `odds_ratio`가 1에 가까운 단어 추출 - 대부분 보편적인 의미를 지니는 단어 ```r frequency_wide %>% arrange(abs(1 - odds_ratio)) %>% head(10) ``` ``` ## # A tibble: 10 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 때문 4 3 0.00218 0.00221 0.989 ## 2 강화 3 2 0.00175 0.00165 1.06 ## 3 부담 3 2 0.00175 0.00165 1.06 ## 4 세계 3 2 0.00175 0.00165 1.06 ## 5 책임 3 2 0.00175 0.00165 1.06 ## 6 협력 3 2 0.00175 0.00165 1.06 ## 7 거대 2 1 0.00131 0.00110 1.19 ## 8 교체 2 1 0.00131 0.00110 1.19 ## 9 근본적 2 1 0.00131 0.00110 1.19 ## 10 기반 2 1 0.00131 0.00110 1.19 ``` --- #### 중요도가 비슷한 단어 살펴보기 - 중요도가 비슷하면서 빈도가 높은 단어: 두 텍스트에서 모두 강조한 단어 ```r frequency_wide %>% filter(moon >= 5 & park >= 5) %>% arrange(abs(1 - odds_ratio)) %>% head(10) ``` ``` ## # A tibble: 10 x 6 ## word moon park ratio_moon ratio_park odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> ## 1 사회 14 9 0.00655 0.00552 1.19 ## 2 사람 9 9 0.00436 0.00552 0.791 ## 3 경제 15 15 0.00698 0.00883 0.791 ## 4 지원 5 5 0.00262 0.00331 0.791 ## 5 우리 17 10 0.00786 0.00607 1.29 ## 6 불안 7 8 0.00349 0.00496 0.703 ## 7 산업 9 5 0.00436 0.00331 1.32 ## 8 대한민국 11 6 0.00524 0.00386 1.36 ## 9 국가 7 10 0.00349 0.00607 0.576 ## 10 교육 6 9 0.00306 0.00552 0.554 ``` --- name: 03-3 class: title1 03-3 로그 오즈비로 단어 비교하기 --- ##### 로그 오즈비(log odds ratio) - 오즈비에 로그를 취한 값 - 단어의 오즈비가 1보다 크면 `+`, 1보다 작으면 `-`가 됨 - 단어가 두 텍스트 중 어디에서 비중이 큰지에 따라 서로 다른 부호 - `"moon"`에서 비중이 커서 `odds_ratio`가 1보다 큰 단어 `+` - `"park"`에서 비중이 커서 `odds_ratio`가 1보다 작은 단어 `-` <br> <img src="Image/etc/03_3_table1.png" width="60%" height="60%" /> --- ##### 로그 오즈비(log odds ratio) - 오즈비에 로그를 취한 값 - 단어의 오즈비가 1보다 크면 `+`, 1보다 작으면 `-`가 됨 - 단어가 두 텍스트 중 어디에서 비중이 큰지에 따라 서로 다른 부호 - `"moon"`에서 비중이 커서 `odds_ratio`가 1보다 큰 단어 `+` - `"park"`에서 비중이 커서 `odds_ratio`가 1보다 작은 단어 `-` <br> .center[ `$${\large\text{odds ratio} = \frac{\left(\frac{n+1}{\text{total}+1}\right)_\text{Text A}} {\left(\frac{n+1}{\text{total}+1}\right)_\text{Text B}}}$$` ] --- ##### 로그 오즈비(log odds ratio) - 오즈비에 로그를 취한 값 - 단어의 오즈비가 1보다 크면 `+`, 1보다 작으면 `-`가 됨 - 단어가 두 텍스트 중 어디에서 비중이 큰지에 따라 서로 다른 부호 - `"moon"`에서 비중이 커서 `odds_ratio`가 1보다 큰 단어 `+` - `"park"`에서 비중이 커서 `odds_ratio`가 1보다 작은 단어 `-` <br> .center[ `$${\large\text{log odds ratio} = \log{\left(\frac{\left(\frac{n+1}{\text{total}+1}\right)_\text{Text A}} {\left(\frac{n+1}{\text{total}+1}\right)_\text{Text B}}\right)}}$$` ] --- - 텍스트 차이 분명하게 드러나도록 시각화하는데 활용 - 단어가 어느 텍스트에서 중요한지에 따라 막대를 반대 방향으로 표현 <img src="Image/03/03_3_1.png" width="60%" height="60%" /> --- #### 로그 오즈비 구하기 ```r frequency_wide <- frequency_wide %>% mutate(log_odds_ratio = log(odds_ratio)) frequency_wide ``` ``` ## # A tibble: 955 x 7 ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> ## 1 가동 1 0 0.000873 0.000552 1.58 0.459 ## 2 가사 1 0 0.000873 0.000552 1.58 0.459 ## 3 가슴 2 0 0.00131 0.000552 2.37 0.865 ## 4 가족 1 1 0.000873 0.00110 0.791 -0.234 ## 5 가족구조 1 0 0.000873 0.000552 1.58 0.459 ## 6 가지 4 0 0.00218 0.000552 3.96 1.38 ## 7 가치 3 1 0.00175 0.00110 1.58 0.459 ## 8 각종 1 0 0.000873 0.000552 1.58 0.459 ## 9 감당 1 0 0.000873 0.000552 1.58 0.459 ## 10 강력 3 0 0.00175 0.000552 3.17 1.15 ## # ... with 945 more rows ``` --- - **부호**와 **크기**를 보면 단어가 어느 연설문에서 더 중요한지 알 수 있음 - **0보다 큰 양수일수록 `"moon`"에서 비중이 큼** - 0보다 작은 음수일수록 `"park"`에서 비중이 큼 - 0에 가까우면 두 연설문에서 비중 비슷함 ```r # moon에서 비중이 큰 단어 frequency_wide %>% * arrange(-log_odds_ratio) ``` ``` ## # A tibble: 955 x 7 ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> ## 1 복지국가 8 0 0.00393 0.000552 7.12 1.96 ## 2 세상 6 0 0.00306 0.000552 5.54 1.71 ## 3 여성 6 0 0.00306 0.000552 5.54 1.71 ## 4 정의 6 0 0.00306 0.000552 5.54 1.71 ## 5 강자 5 0 0.00262 0.000552 4.75 1.56 ## 6 공평 5 0 0.00262 0.000552 4.75 1.56 ## 7 대통령의 5 0 0.00262 0.000552 4.75 1.56 ## 8 보통 5 0 0.00262 0.000552 4.75 1.56 ## 9 상생 5 0 0.00262 0.000552 4.75 1.56 ## 10 지방 5 0 0.00262 0.000552 4.75 1.56 ## # ... with 945 more rows ``` --- - 부호와 크기를 보면 단어가 어느 연설문에서 더 중요한지 알 수 있음 - 0보다 큰 양수일수록 `"moon`"에서 비중이 큼 - **0보다 작은 음수일수록 `"park"`에서 비중이 큼** - 0에 가까우면 두 연설문에서 비중 비슷함 ```r # park에서 비중이 큰 단어 frequency_wide %>% * arrange(log_odds_ratio) ``` ``` ## # A tibble: 955 x 7 ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> ## 1 박근혜 0 8 0.000436 0.00496 0.0879 -2.43 ## 2 여러분 2 20 0.00131 0.0116 0.113 -2.18 ## 3 행복 3 23 0.00175 0.0132 0.132 -2.03 ## 4 실천 0 5 0.000436 0.00331 0.132 -2.03 ## 5 정보 0 5 0.000436 0.00331 0.132 -2.03 ## 6 투명 0 5 0.000436 0.00331 0.132 -2.03 ## 7 과제 0 4 0.000436 0.00276 0.158 -1.84 ## 8 국정운영 0 4 0.000436 0.00276 0.158 -1.84 ## 9 시작 0 4 0.000436 0.00276 0.158 -1.84 ## 10 지식 0 4 0.000436 0.00276 0.158 -1.84 ## # ... with 945 more rows ``` --- - 부호와 크기를 보면 단어가 어느 연설문에서 더 중요한지 알 수 있음 - 0보다 큰 양수일수록 `"moon`"에서 비중이 큼 - 0보다 작은 음수일수록 `"park"`에서 비중이 큼 - **0에 가까우면 두 연설문에서 비중 비슷함** ```r # 비중이 비슷한 단어 frequency_wide %>% * arrange(abs(log_odds_ratio)) ``` ``` ## # A tibble: 955 x 7 ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> ## 1 때문 4 3 0.00218 0.00221 0.989 -0.0109 ## 2 강화 3 2 0.00175 0.00165 1.06 0.0537 ## 3 부담 3 2 0.00175 0.00165 1.06 0.0537 ## 4 세계 3 2 0.00175 0.00165 1.06 0.0537 ## 5 책임 3 2 0.00175 0.00165 1.06 0.0537 ## 6 협력 3 2 0.00175 0.00165 1.06 0.0537 ## 7 거대 2 1 0.00131 0.00110 1.19 0.171 ## 8 교체 2 1 0.00131 0.00110 1.19 0.171 ## 9 근본적 2 1 0.00131 0.00110 1.19 0.171 ## 10 기반 2 1 0.00131 0.00110 1.19 0.171 ## # ... with 945 more rows ``` --- .box[ .info[<svg viewBox="0 0 512 512" style="height:1em;position:relative;display:inline-block;top:.1em;fill:#FF7333;" xmlns="http://www.w3.org/2000/svg"> <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> 로그 오즈비 간단히 구하기] ```r frequency_wide <- frequency_wide %>% mutate(log_odds_ratio = log(((moon + 1) / (sum(moon + 1))) / ((park + 1) / (sum(park + 1))))) ``` ] --- #### 로그 오즈비를 이용해 중요한 단어 비교하기 - 두 연설문 각각 `log_odds_ratio` Top 10 추출 ```r top10 <- frequency_wide %>% group_by(president = ifelse(log_odds_ratio > 0, "moon", "park")) %>% slice_max(abs(log_odds_ratio), n = 10, with_ties = F) top10 ``` --- ``` ## # A tibble: 20 x 8 ## # Groups: president [2] ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio president ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> <chr> ## 1 복지국가 8 0 0.00393 0.000552 7.12 1.96 moon ## 2 세상 6 0 0.00306 0.000552 5.54 1.71 moon ## 3 여성 6 0 0.00306 0.000552 5.54 1.71 moon ## 4 정의 6 0 0.00306 0.000552 5.54 1.71 moon ## 5 강자 5 0 0.00262 0.000552 4.75 1.56 moon ## 6 공평 5 0 0.00262 0.000552 4.75 1.56 moon ## 7 대통령의 5 0 0.00262 0.000552 4.75 1.56 moon ## 8 보통 5 0 0.00262 0.000552 4.75 1.56 moon ## 9 상생 5 0 0.00262 0.000552 4.75 1.56 moon ## 10 지방 5 0 0.00262 0.000552 4.75 1.56 moon ## 11 박근혜 0 8 0.000436 0.00496 0.0879 -2.43 park ## 12 여러분 2 20 0.00131 0.0116 0.113 -2.18 park ## 13 행복 3 23 0.00175 0.0132 0.132 -2.03 park ## 14 실천 0 5 0.000436 0.00331 0.132 -2.03 park ## 15 정보 0 5 0.000436 0.00331 0.132 -2.03 park ## 16 투명 0 5 0.000436 0.00331 0.132 -2.03 park ## 17 과제 0 4 0.000436 0.00276 0.158 -1.84 park ## 18 국정운영 0 4 0.000436 0.00276 0.158 -1.84 park ## 19 시작 0 4 0.000436 0.00276 0.158 -1.84 park ## 20 지식 0 4 0.000436 0.00276 0.158 -1.84 park ``` --- ##### 주요 변수 추출 ```r top10 %>% arrange(-log_odds_ratio) %>% select(word, log_odds_ratio, president) ``` ``` ## # A tibble: 20 x 3 ## # Groups: president [2] ## word log_odds_ratio president ## <chr> <dbl> <chr> ## 1 복지국가 1.96 moon ## 2 세상 1.71 moon ## 3 여성 1.71 moon ## 4 정의 1.71 moon ## 5 강자 1.56 moon ## 6 공평 1.56 moon ## 7 대통령의 1.56 moon ## 8 보통 1.56 moon ## 9 상생 1.56 moon ## 10 지방 1.56 moon ## # ... with 10 more rows ``` --- ``` ## # A tibble: 20 x 3 ## # Groups: president [2] ## word log_odds_ratio president ## <chr> <dbl> <chr> *## 1 복지국가 1.96 moon *## 2 세상 1.71 moon *## 3 여성 1.71 moon *## 4 정의 1.71 moon *## 5 강자 1.56 moon *## 6 공평 1.56 moon *## 7 대통령의 1.56 moon *## 8 보통 1.56 moon *## 9 상생 1.56 moon *## 10 지방 1.56 moon ## 11 과제 -1.84 park ## 12 국정운영 -1.84 park ## 13 시작 -1.84 park ## 14 지식 -1.84 park ## 15 행복 -2.03 park ## 16 실천 -2.03 park ## 17 정보 -2.03 park ## 18 투명 -2.03 park ## 19 여러분 -2.18 park ## 20 박근혜 -2.43 park ``` --- ``` ## # A tibble: 20 x 3 ## # Groups: president [2] ## word log_odds_ratio president ## <chr> <dbl> <chr> ## 1 복지국가 1.96 moon ## 2 세상 1.71 moon ## 3 여성 1.71 moon ## 4 정의 1.71 moon ## 5 강자 1.56 moon ## 6 공평 1.56 moon ## 7 대통령의 1.56 moon ## 8 보통 1.56 moon ## 9 상생 1.56 moon ## 10 지방 1.56 moon *## 11 과제 -1.84 park *## 12 국정운영 -1.84 park *## 13 시작 -1.84 park *## 14 지식 -1.84 park *## 15 행복 -2.03 park *## 16 실천 -2.03 park *## 17 정보 -2.03 park *## 18 투명 -2.03 park *## 19 여러분 -2.18 park *## 20 박근혜 -2.43 park ``` --- .box[ **오즈비 기준 상·하위 10개 추출했을 때와 단어 동일** ```r frequency_wide %>% filter(rank(odds_ratio) <= 10 | rank(-odds_ratio) <= 10) %>% arrange(-odds_ratio) ``` ] --- .box[ <br-back-20> ``` ## # A tibble: 20 x 7 ## word moon park ratio_moon ratio_park odds_ratio log_odds_ratio ## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl> ## 1 복지국가 8 0 0.00393 0.000552 7.12 1.96 ## 2 세상 6 0 0.00306 0.000552 5.54 1.71 ## 3 여성 6 0 0.00306 0.000552 5.54 1.71 ## 4 정의 6 0 0.00306 0.000552 5.54 1.71 ## 5 강자 5 0 0.00262 0.000552 4.75 1.56 ## 6 공평 5 0 0.00262 0.000552 4.75 1.56 ## 7 대통령의 5 0 0.00262 0.000552 4.75 1.56 ## 8 보통 5 0 0.00262 0.000552 4.75 1.56 ## 9 상생 5 0 0.00262 0.000552 4.75 1.56 ## 10 지방 5 0 0.00262 0.000552 4.75 1.56 ## 11 과제 0 4 0.000436 0.00276 0.158 -1.84 ## 12 국정운영 0 4 0.000436 0.00276 0.158 -1.84 ## 13 시작 0 4 0.000436 0.00276 0.158 -1.84 ## 14 지식 0 4 0.000436 0.00276 0.158 -1.84 ## 15 행복 3 23 0.00175 0.0132 0.132 -2.03 ## 16 실천 0 5 0.000436 0.00331 0.132 -2.03 ## 17 정보 0 5 0.000436 0.00331 0.132 -2.03 ## 18 투명 0 5 0.000436 0.00331 0.132 -2.03 ## 19 여러분 2 20 0.00131 0.0116 0.113 -2.18 ## 20 박근혜 0 8 0.000436 0.00496 0.0879 -2.43 ``` ] --- #### 막대 그래프 만들기 - 단어가 어느 연설문에서 중요한지에 따라 서로 다른 축 방향으로 표현됨 ```r ggplot(top10, aes(x = reorder(word, log_odds_ratio), y = log_odds_ratio, fill = president)) + geom_col() + coord_flip() + labs(x = NULL) + theme(text = element_text(family = "nanumgothic")) ``` <img src="03-comparing_files/figure-html/unnamed-chunk-97-1.png" width="45%" /> --- <br> <img src="03-comparing_files/figure-html/unnamed-chunk-98-1.png" width="80%" /> --- name: 03-4 class: title1 03-4 TF-IDF: <br> 여러 텍스트의 단어 비교하기 --- ##### 오즈비의 한계 - 두 조건의 확률을 이용해 계산 - 여러 텍스트 비교하기 불편 - 두 개 이상의 텍스트 비교할 때는 **TF-IDF** 활용 -- ##### 중요한 단어? - 흔하지 않으면서도 특정 텍스트에서는 자주 사용된 단어 - 텍스트가 다른 텍스트와 구별되는 특징, 개성을 드러내는 단어 - ex) 자기소개서: "저는" vs "스카이다이빙" --- #### TF-IDF(Term Frequency - Inverse Document Frequency) - 어떤 단어가 흔하지 않으면서도 특정 텍스트에서는 자주 사용된 정도를 나타낸 지표 - 텍스트의 개성을 드러내는 주요 단어를 찾는데 활용 -- ##### TF(Term Frequency) - 단어가 특정 텍스트에 사용된 횟수 - 단어 빈도 <br> <br-back-30> <img src="Image/etc/03_4_table1.png" width="50%" height="50%" /> --- ##### DF와 IDF - **DF(Document Frequency)** - 단어가 사용된 텍스트 수 - '문서 빈도' - 클수록 여러 문서에 흔하게 사용된 일반적인 단어 -- - **IDF(Inverse Document Frequency)** - '역문서 빈도' - (1) 전체 문서 수(N)에서 DF가 차지하는 비중을 구함 - (2) 그 값의 역수를 취함 - (3) 로그를 취함 - DF가 클수록 작아지고, 반대로 DF가 작을수록 커짐 - 클수록 드물게 사용되는 특이한 단어, 작을수록 흔하게 사용되는 일반적인 단어 <br> <br-back-30> `$${\large\text{IDF} = \log{\frac{{\text{N}}}{{\text{DF}}}}}$$` --- ##### DF와 IDF <br> <br-back-20> <img src="Image/etc/03_4_table2.png" width="50%" height="50%" /> <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> 소수점 둘째 자리에서 반올림하여 표기 --- ##### TF-IDF - TF(단어 빈도)와 IDF(역 문서 빈도)를 곱한 값 - TF: 단어가 분석 대상이 되는 텍스트 내에서 많이 사용될수록 커짐 - IDF: 단어가 사용된 텍스트가 드물수록 커짐 -- <br> <br-back-20> `$${\large\text{TF-IDF} = TF{\times}\log\frac{{\text{N}}}{{\text{DF}}}}$$` <br> --- ##### TF-IDF - **흔하지 않은 단어**인데 **특정 텍스트에서 자주 사용**될수록 큰 값 - TF-IDF가 큰 단어를 보면 다른 텍스트와 구별되는 특징을 알 수 있음 <br> <br-back-30> <img src="Image/etc/03_4_table3.png" width="60%" height="60%" style="display: block; margin: auto;" /> .center[ <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> 소수점 둘째 자리에서 반올림하여 표기 ] --- #### TF-IDF 구하기 ##### 1. 단어 빈도 구하기 - `speeches_presidents.csv` : 역대 대통령의 대선 출마 선언문 - `readr::read_csv()` 데이터를 다루기 편한 tibble 구조로 만들어 줌, `read.csv()`보다 빠름 ```r # 데이터 불러오기 install.packages("readr") library(readr) raw_speeches <- read_csv("speeches_presidents.csv") raw_speeches ``` ``` ## # A tibble: 4 x 2 ## president value ## <chr> <chr> ## 1 문재인 "정권교체 하겠습니다! 정치교체 하겠~ ## 2 박근혜 "존경하는 국민 여러분! 저는 오늘, 국~ ## 3 이명박 "존경하는 국민 여러분, 사랑하는 한나~ ## 4 노무현 "어느때인가 부터 제가 대통령이 되겠다~ ``` --- ```r # 기본적인 전처리 speeches <- raw_speeches %>% mutate(value = str_replace_all(value, "[^가-힣]", " "), value = str_squish(value)) # 토큰화 speeches <- speeches %>% unnest_tokens(input = value, output = word, token = extractNoun) # 단어 빈도 구하기 frequecy <- speeches %>% count(president, word) %>% filter(str_count(word) > 1) frequecy ``` --- ``` ## # A tibble: 1,513 x 3 ## president word n ## <chr> <chr> <int> ## 1 노무현 가슴 2 ## 2 노무현 가훈 2 ## 3 노무현 갈등 1 ## 4 노무현 감옥 1 ## 5 노무현 강자 1 ## 6 노무현 개편 4 ## 7 노무현 개혁 4 ## 8 노무현 건국 1 ## 9 노무현 경선 1 ## 10 노무현 경쟁 1 ## # ... with 1,503 more rows ``` --- #### 3.4.2 TF-IDF 구하기 - `tidytext::bind_tf_idf()` - `term` : 단어 - `document` : 텍스트 구분 기준 - `n` : 단어 빈도 ```r frequecy <- frequecy %>% bind_tf_idf(term = word, # 단어 document = president, # 텍스트 구분 기준 n = n) %>% # 단어 빈도 arrange(-tf_idf) frequecy ``` --- ``` ## # A tibble: 1,513 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 노무현 공식 6 0.0163 1.39 0.0227 ## 2 노무현 비젼 6 0.0163 1.39 0.0227 ## 3 노무현 정계 6 0.0163 1.39 0.0227 ## 4 이명박 리더십 6 0.0158 1.39 0.0219 ## 5 노무현 권력 9 0.0245 0.693 0.0170 ## 6 노무현 개편 4 0.0109 1.39 0.0151 ## 7 이명박 당원 4 0.0105 1.39 0.0146 ## 8 이명박 동지 4 0.0105 1.39 0.0146 ## 9 이명박 일류국가 4 0.0105 1.39 0.0146 ## 10 박근혜 박근혜 8 0.00962 1.39 0.0133 ## # ... with 1,503 more rows ``` <svg viewBox="0 0 352 512" style="height:1em;position:relative;display:inline-block;top:.1em;" xmlns="http://www.w3.org/2000/svg"> <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> `tf`: 대상 텍스트의 전체 단어 수에서 해당 단어의 수가 차지하는 '비중'. <br> 텍스트에 사용된 전체 단어 수가 많을수록 작아짐 --- ##### TF-IDF가 높은 단어 살펴보기 - 텍스트의 특징을 드러내는 중요한 단어 - 각 대통령이 다른 대통령들과 달리 무엇을 강조했는지 알 수 있음 ```r frequecy %>% filter(president == "문재인") ``` ``` ## # A tibble: 688 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 문재인 복지국가 8 0.00608 1.39 0.00843 ## 2 문재인 여성 6 0.00456 1.39 0.00633 ## 3 문재인 공평 5 0.00380 1.39 0.00527 ## 4 문재인 담쟁이 5 0.00380 1.39 0.00527 ## 5 문재인 대통령의 5 0.00380 1.39 0.00527 ## 6 문재인 보통 5 0.00380 1.39 0.00527 ## 7 문재인 상생 5 0.00380 1.39 0.00527 ## 8 문재인 우리나라 10 0.00760 0.693 0.00527 ## 9 문재인 지방 5 0.00380 1.39 0.00527 ## 10 문재인 확대 10 0.00760 0.693 0.00527 ## # ... with 678 more rows ``` --- ##### TF-IDF가 높은 단어 살펴보기 - 텍스트의 특징을 드러내는 중요한 단어 - 각 대통령이 다른 대통령들과 달리 무엇을 강조했는지 알 수 있음 ```r frequecy %>% filter(president == "박근혜") ``` ``` ## # A tibble: 407 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 박근혜 박근혜 8 0.00962 1.39 0.0133 ## 2 박근혜 정보 5 0.00601 1.39 0.00833 ## 3 박근혜 투명 5 0.00601 1.39 0.00833 ## 4 박근혜 행복 23 0.0276 0.288 0.00795 ## 5 박근혜 교육 9 0.0108 0.693 0.00750 ## 6 박근혜 국정운영 4 0.00481 1.39 0.00666 ## 7 박근혜 정부 17 0.0204 0.288 0.00588 ## 8 박근혜 개개인 3 0.00361 1.39 0.00500 ## 9 박근혜 개인 3 0.00361 1.39 0.00500 ## 10 박근혜 공개 3 0.00361 1.39 0.00500 ## # ... with 397 more rows ``` --- ##### TF-IDF가 높은 단어 살펴보기 - 텍스트의 특징을 드러내는 중요한 단어 - 각 대통령이 다른 대통령들과 달리 무엇을 강조했는지 알 수 있음 ```r frequecy %>% filter(president == "이명박") ``` ``` ## # A tibble: 202 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 이명박 리더십 6 0.0158 1.39 0.0219 ## 2 이명박 당원 4 0.0105 1.39 0.0146 ## 3 이명박 동지 4 0.0105 1.39 0.0146 ## 4 이명박 일류국가 4 0.0105 1.39 0.0146 ## 5 이명박 한나라 7 0.0184 0.693 0.0128 ## 6 이명박 나라 15 0.0395 0.288 0.0114 ## 7 이명박 도약 3 0.00789 1.39 0.0109 ## 8 이명박 일하 3 0.00789 1.39 0.0109 ## 9 이명박 사랑 5 0.0132 0.693 0.00912 ## 10 이명박 인생 5 0.0132 0.693 0.00912 ## # ... with 192 more rows ``` --- ##### TF-IDF가 높은 단어 살펴보기 - 텍스트의 특징을 드러내는 중요한 단어 - 각 대통령이 다른 대통령들과 달리 무엇을 강조했는지 알 수 있음 ```r frequecy %>% filter(president == "노무현") ``` ``` ## # A tibble: 216 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 노무현 공식 6 0.0163 1.39 0.0227 ## 2 노무현 비젼 6 0.0163 1.39 0.0227 ## 3 노무현 정계 6 0.0163 1.39 0.0227 ## 4 노무현 권력 9 0.0245 0.693 0.0170 ## 5 노무현 개편 4 0.0109 1.39 0.0151 ## 6 노무현 국회의원 3 0.00817 1.39 0.0113 ## 7 노무현 남북대화 3 0.00817 1.39 0.0113 ## 8 노무현 총리 3 0.00817 1.39 0.0113 ## 9 노무현 가훈 2 0.00545 1.39 0.00755 ## 10 노무현 개혁 4 0.0109 0.693 0.00755 ## # ... with 206 more rows ``` --- ##### TF-IDF가 낮은 단어 살펴보기 - 역대 대통령들이 공통적으로 사용한 흔한 단어, 범용 단어 ```r frequecy %>% filter(president == "문재인") %>% arrange(tf_idf) ``` ``` ## # A tibble: 688 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 문재인 경쟁 6 0.00456 0 0 ## 2 문재인 경제 15 0.0114 0 0 ## 3 문재인 고통 4 0.00304 0 0 ## 4 문재인 과거 1 0.000760 0 0 ## 5 문재인 국민 21 0.0160 0 0 ## 6 문재인 기회 5 0.00380 0 0 ## 7 문재인 대통령 12 0.00913 0 0 ## 8 문재인 동안 2 0.00152 0 0 ## 9 문재인 들이 9 0.00684 0 0 ## 10 문재인 마음 2 0.00152 0 0 ## # ... with 678 more rows ``` --- ##### TF-IDF가 낮은 단어 살펴보기 - 역대 대통령들이 공통적으로 사용한 흔한 단어, 범용 단어 ```r frequecy %>% filter(president == "박근혜") %>% arrange(tf_idf) ``` ``` ## # A tibble: 407 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 박근혜 경쟁 1 0.00120 0 0 ## 2 박근혜 경제 15 0.0180 0 0 ## 3 박근혜 고통 4 0.00481 0 0 ## 4 박근혜 과거 2 0.00240 0 0 ## 5 박근혜 국민 72 0.0865 0 0 ## 6 박근혜 기회 1 0.00120 0 0 ## 7 박근혜 대통령 3 0.00361 0 0 ## 8 박근혜 동안 3 0.00361 0 0 ## 9 박근혜 들이 3 0.00361 0 0 ## 10 박근혜 마음 3 0.00361 0 0 ## # ... with 397 more rows ``` --- #### 막대 그래프 만들기 ```r # 주요 단어 추출 top10 <- frequecy %>% group_by(president) %>% slice_max(tf_idf, n = 10, with_ties = F) # 그래프 순서 정하기 top10$president <- factor(top10$president, levels = c("문재인", "박근혜", "이명박", "노무현")) # 막대 그래프 만들기 ggplot(top10, aes(x = reorder_within(word, tf_idf, president), y = tf_idf, fill = president)) + geom_col(show.legend = F) + coord_flip() + facet_wrap(~ president, scales = "free", ncol = 2) + scale_x_reordered() + labs(x = NULL) + theme(text = element_text(family = "nanumgothic")) ``` --- <img src="03-comparing_files/figure-html/unnamed-chunk-116-1.png" width="75%" /> --- class: title1 정리하기 --- ### 정리하기 ##### 1. 단어 빈도 비교하기 ```r # 토큰화 speeches <- speeches %>% unnest_tokens(input = value, output = word, token = extractNoun) # 하위 집단별 단어 빈도 구하기 frequency <- speeches %>% count(president, word) %>% filter(str_count(word) > 1) # 가장 많이 사용된 단어 추출 top10 <- frequency %>% group_by(president) %>% slice_max(n, n = 10, with_ties = F) ``` --- ### 정리하기 ##### 2. 로그 오즈비로 단어 비교하기 ```r # long form을 wide form으로 변환 frequency_wide <- frequency %>% pivot_wider(names_from = president, values_from = n, values_fill = list(n = 0)) # 로그 오즈비 구하기 frequency_wide <- frequency_wide %>% mutate(log_odds_ratio = log(((moon + 1) / (sum(moon + 1))) / ((park + 1) / (sum(park + 1))))) # 상대적으로 중요한 단어 추출 top10 <- frequency_wide %>% group_by(president = ifelse(log_odds_ratio > 0, "moon", "park")) %>% slice_max(abs(log_odds_ratio), n = 10, with_ties = F) ``` --- ### 정리하기 ##### 3. TF-IDF로 단어 비교하기 ```r # TF-IDF 구하기 frequecy <- frequecy %>% bind_tf_idf(term = word, document = president, n = n) %>% arrange(-tf_idf) # 상대적으로 중요한 단어 추출 top10 <- frequecy %>% arrange(tf_idf) %>% group_by(president) %>% slice_max(tf_idf, n = 10, with_ties = F) ``` --- class: title1 분석 도전 --- ### 분석 도전(1/2) **Q1. 역대 대통령의 대선 출마 선언문을 담은 `speeches_presidents.csv`를 이용해 문제를 해결해 보세요.** Q1.1 `speeches_presidents.csv`를 불러와 이명박 전 대통령과 노무현 전 대통령의 연설문을 추출하고 분석에 적합하게 전처리하세요. Q1.2 연설문에서 명사를 추출한 다음 연설문별 단어 빈도를 구하세요. Q1.3 로그 오즈비를 이용해 두 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. Q1.4 두 연설문에서 상대적으로 중요한 단어를 나타낸 막대 그래프를 만드세요. --- Q1.1 `speeches_presidents.csv`를 불러와 이명박 전 대통령과 노무현 전 대통령의 연설문을 추출하고 분석에 적합하게 전처리하세요. ```r # 데이터 불러오기 library(readr) raw_speeches <- read_csv("speeches_presidents.csv") # 전처리 library(dplyr) library(stringr) speeches <- raw_speeches %>% filter(president %in% c("이명박", "노무현")) %>% mutate(value = str_replace_all(value, "[^가-힣]", " "), value = str_squish(value)) speeches ``` ``` ## # A tibble: 2 x 2 ## president value ## <chr> <chr> ## 1 이명박 존경하는 국민 여러분 사랑하는 한나라당 당원 동지 여러분 저는 오늘 ~ ## 2 노무현 어느때인가 부터 제가 대통령이 되겠다고 말을 하기 시작했습니다 많은 ~ ``` --- Q1.2 연설문에서 명사를 추출한 다음 연설문별 단어 빈도를 구하세요. <br-back-10> ```r # 명사 추출 library(tidytext) library(KoNLP) speeches <- speeches %>% unnest_tokens(input = value, output = word, token = extractNoun) speeches ``` <br-back-10> ``` ## # A tibble: 1,002 x 2 ## president word ## <chr> <chr> ## 1 이명박 존경 ## 2 이명박 하 ## 3 이명박 국민 ## 4 이명박 여러분 ## 5 이명박 사랑 ## 6 이명박 하 ## 7 이명박 한나라 ## 8 이명박 당 ## 9 이명박 당원 ## 10 이명박 동지 ## # ... with 992 more rows ``` --- Q1.2 연설문에서 명사를 추출한 다음 연설문별 단어 빈도를 구하세요. ```r # 연설문별 단어 빈도 구하기 frequency <- speeches %>% count(president, word) %>% filter(str_count(word) > 1) frequency ``` ``` ## # A tibble: 418 x 3 ## president word n ## <chr> <chr> <int> ## 1 노무현 가슴 2 ## 2 노무현 가훈 2 ## 3 노무현 갈등 1 ## 4 노무현 감옥 1 ## 5 노무현 강자 1 ## 6 노무현 개편 4 ## 7 노무현 개혁 4 ## 8 노무현 건국 1 ## 9 노무현 경선 1 ## 10 노무현 경쟁 1 ## # ... with 408 more rows ``` --- Q1.3 로그 오즈비를 이용해 두 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # long form을 wide form으로 변환 library(tidyr) frequency_wide <- frequency %>% pivot_wider(names_from = president, # 변수명으로 만들 값 values_from = n, # 변수에 채워 넣을 값 values_fill = list(n = 0)) # 결측치 0으로 변환 frequency_wide ``` ``` ## # A tibble: 382 x 3 ## word 노무현 이명박 ## <chr> <int> <int> ## 1 가슴 2 0 ## 2 가훈 2 0 ## 3 갈등 1 0 ## 4 감옥 1 0 ## 5 강자 1 0 ## 6 개편 4 0 ## 7 개혁 4 0 ## 8 건국 1 0 ## 9 경선 1 0 ## 10 경쟁 1 3 ## # ... with 372 more rows ``` --- Q1.3 로그 오즈비를 이용해 두 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # 로그 오즈비 구하기 frequency_wide <- frequency_wide %>% mutate(log_odds_ratio = log(((이명박 + 1) / (sum(이명박 + 1))) / ((노무현 + 1) / (sum(노무현 + 1))))) frequency_wide ``` ``` ## # A tibble: 382 x 4 ## word 노무현 이명박 log_odds_ratio ## <chr> <int> <int> <dbl> ## 1 가슴 2 0 -1.12 ## 2 가훈 2 0 -1.12 ## 3 갈등 1 0 -0.710 ## 4 감옥 1 0 -0.710 ## 5 강자 1 0 -0.710 ## 6 개편 4 0 -1.63 ## 7 개혁 4 0 -1.63 ## 8 건국 1 0 -0.710 ## 9 경선 1 0 -0.710 ## 10 경쟁 1 3 0.676 ## # ... with 372 more rows ``` --- Q1.3 로그 오즈비를 이용해 두 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # 상대적으로 중요한 단어 추출 top10 <- frequency_wide %>% group_by(president = ifelse(log_odds_ratio > 0, "lee", "roh")) %>% slice_max(abs(log_odds_ratio), n = 10, with_ties = F) top10 ``` --- ``` ## # A tibble: 20 x 5 ## # Groups: president [2] ## word 노무현 이명박 log_odds_ratio president ## <chr> <int> <int> <dbl> <chr> ## 1 나라 0 15 2.76 lee ## 2 대한민국 0 12 2.55 lee ## 3 세계 1 13 1.93 lee ## 4 리더십 0 6 1.93 lee ## 5 여러분 1 11 1.77 lee ## 6 국가 0 5 1.77 lee ## 7 발전 0 5 1.77 lee ## 8 사랑 0 5 1.77 lee ## 9 인생 0 5 1.77 lee ## 10 당원 0 4 1.59 lee ## 11 권력 9 0 -2.32 roh ## 12 정치 8 0 -2.21 roh ## 13 공식 6 0 -1.96 roh ## 14 비젼 6 0 -1.96 roh ## 15 정계 6 0 -1.96 roh ## 16 개편 4 0 -1.63 roh ## 17 개혁 4 0 -1.63 roh ## 18 당당 4 0 -1.63 roh ## 19 정의 4 0 -1.63 roh ## 20 지역 4 0 -1.63 roh ``` --- Q1.4 두 연설문에서 상대적으로 중요한 단어를 나타낸 막대 그래프를 만드세요. ```r library(ggplot2) ggplot(top10, aes(x = reorder(word, log_odds_ratio), y = log_odds_ratio, fill = president)) + geom_col() + coord_flip () + labs(x = NULL) ``` <img src="03-comparing_files/figure-html/unnamed-chunk-129-1.png" width="50%" /> --- <img src="03-comparing_files/figure-html/unnamed-chunk-130-1.png" width="90%" /> --- ### 분석 도전(2/2) **Q2. 역대 대통령의 취임사를 담은 `inaugural_address.csv`를 이용해 문제를 해결해 보세요.** Q2.1 `inaugural_address.csv`를 불러와 분석에 적합하게 전처리하고 연설문에서 명사를 추출하세요. Q2.2 TF-IDF를 이용해 각 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. Q2.3 각 연설문에서 상대적으로 중요한 단어를 나타낸 막대 그래프를 만드세요. --- Q2.1 `inaugural_address.csv`를 불러와 분석에 적합하게 전처리하고 연설문에서 명사를 추출하세요. ```r # 데이터 불러오기 library(readr) raw_speeches <- read_csv("inaugural_address.csv") # 전처리 library(dplyr) library(stringr) speeches <- raw_speeches %>% mutate(value = str_replace_all(value, "[^가-힣]", " "), value = str_squish(value)) speeches ``` ``` ## # A tibble: 4 x 2 ## president value ## <chr> <chr> ## 1 문재인 국민께 드리는 말씀 존경하고 사랑하는 국민 여러분 감사합니다 국민 여~ ## 2 박근혜 희망의 새 시대를 열겠습니다 존경하는 국민여러분 만 해외동포 여러분 ~ ## 3 이명박 존경하는 국민 여러분 만 해외동포 여러분 이 자리에 참석하신 노무현 ~ ## 4 노무현 존경하는 국민 여러분 오늘 저는 대한민국의 제 대 대통령에 취임하기 ~ ``` --- Q2.1 `inaugural_address.csv`를 불러와 분석에 적합하게 전처리하고 연설문에서 명사를 추출하세요. ```r # 명사 기준 토큰화 library(tidytext) library(KoNLP) speeches <- speeches %>% unnest_tokens(input = value, output = word, token = extractNoun) speeches ``` --- ``` ## # A tibble: 4,121 x 2 ## president word ## <chr> <chr> ## 1 문재인 국민 ## 2 문재인 말씀 ## 3 문재인 존경 ## 4 문재인 사랑 ## 5 문재인 하 ## 6 문재인 국민 ## 7 문재인 여러분 ## 8 문재인 감사 ## 9 문재인 국민 ## 10 문재인 여러분 ## # ... with 4,111 more rows ``` --- Q2.2 TF-IDF를 이용해 각 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # 단어 빈도 구하기 frequecy <- speeches %>% count(president, word) %>% filter(str_count(word) > 1) frequecy ``` ``` ## # A tibble: 1,657 x 3 ## president word n ## <chr> <chr> <int> ## 1 노무현 가난 1 ## 2 노무현 가능 1 ## 3 노무현 가일 1 ## 4 노무현 가지 1 ## 5 노무현 각국 1 ## 6 노무현 갈등 1 ## 7 노무현 갈림길 1 ## 8 노무현 감사 4 ## 9 노무현 강구 2 ## 10 노무현 강국 1 ## # ... with 1,647 more rows ``` --- Q2.2 TF-IDF를 이용해 각 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # TF-IDF 구하기 frequecy <- frequecy %>% bind_tf_idf(term = word, # 단어 document = president, # 텍스트 구분 변수 n = n) %>% # 단어 빈도 arrange(-tf_idf) frequecy ``` ``` ## # A tibble: 1,657 x 6 ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 박근혜 행복 21 0.0279 0.693 0.0193 ## 2 노무현 동북아 18 0.0231 0.693 0.0160 ## 3 박근혜 창조경제 8 0.0106 1.39 0.0147 ## 4 노무현 번영 6 0.00770 1.39 0.0107 ## 5 문재인 머리 3 0.00711 1.39 0.00986 ## 6 문재인 문재인 3 0.00711 1.39 0.00986 ## 7 이명박 선진화 8 0.00668 1.39 0.00927 ## 8 박근혜 개개인 5 0.00663 1.39 0.00919 ## 9 박근혜 경제부흥 5 0.00663 1.39 0.00919 ## 10 박근혜 희망 10 0.0133 0.693 0.00919 ## # ... with 1,647 more rows ``` --- Q2.2 TF-IDF를 이용해 각 연설문에서 상대적으로 중요한 단어를 10개씩 추출하세요. ```r # 상대적으로 중요한 단어 추출 top10 <- frequecy %>% group_by(president) %>% slice_max(tf_idf, n = 10, with_ties = F) head(top10) ``` ``` ## # A tibble: 6 x 6 ## # Groups: president [1] ## president word n tf idf tf_idf ## <chr> <chr> <int> <dbl> <dbl> <dbl> ## 1 노무현 동북아 18 0.0231 0.693 0.0160 ## 2 노무현 번영 6 0.00770 1.39 0.0107 ## 3 노무현 도약 3 0.00385 1.39 0.00534 ## 4 노무현 유럽연합 3 0.00385 1.39 0.00534 ## 5 노무현 중앙 3 0.00385 1.39 0.00534 ## 6 노무현 타협 3 0.00385 1.39 0.00534 ``` --- Q2.3 각 연설문에서 상대적으로 중요한 단어를 나타낸 막대 그래프를 만드세요. ```r library(ggplot2) ggplot(top10, aes(x = reorder_within(word, tf_idf, president), y = tf_idf, fill = president)) + geom_col(show.legend = F) + coord_flip () + facet_wrap(~ president, scales = "free", ncol = 2) + scale_x_reordered() + labs(x = NULL) ``` <img src="03-comparing_files/figure-html/unnamed-chunk-138-1.png" width="35%" /> --- <img src="03-comparing_files/figure-html/unnamed-chunk-139-1.png" width="75%" /> --- class: title0 끝