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 02 <br> 형태소 분석기를 이용한 <br> 단어 빈도 분석 --- class: title0-2 We'll make <br-back-10> <img src="Image/02/01_2_1.png" width="60%" height="60%" /> --- class: title0-2 and <br-back-40> <img src="Image/02/01_2_2.png" width="60%" height="60%" /> --- <br> .large2[.font-jua[목차]] .large[.font-jua[02-1 형태소 분석]]([link](#02-1)) .large[.font-jua[02-2 명사 빈도 분석하기]]([link](#02-2)) .large[.font-jua[02-3 특정 단어가 사용된 문장 살펴보기]]([link](#02-3)) --- name: 02-1 class: title1 02-1 형태소 분석 --- #### 띄어쓰기 기준 토큰화의 문제 - 의미를 지니지 않는 서술어가 가장 많이 추출됨 - ex) '합니다', '있습니다' -- #### 형태소 분석(Morphological Analysis) - 문장에서 형태소를 추출해 명사, 동사, 형용사 등 품사로 분류하는 작업 - 특히 명사를 보고 문장 내용 파악 - 형태소(Morpheme) - 의미를 가진 가장 작은 말의 단위 - 더 나누면 뜻이 없는 문자가 됨 --- #### `KoNLP` 한글 형태소 분석 패키지 설치하기 ##### 1. 자바와 rJava 패키지 설치하기 ```r install.packages("multilinguer") library(multilinguer) install_jdk() ``` ##### 2. KoNLP 의존성 패키지 설치하기 ```r install.packages(c("stringr", "hash", "tau", "Sejong", "RSQLite", "devtools"), type = "binary") ``` ##### 3. `KoNLP` 패키지 설치하기 ```r install.packages("remotes") remotes::install_github("haven-jeon/KoNLP", upgrade = "never", INSTALL_opts = c("--no-multiarch")) library(KoNLP) ``` --- #### `KoNLP` 한글 형태소 분석 패키지 설치하기 ##### 4. 형태소 사전 설정하기 NIA 사전: 120만여 개 단어로 구성된 형태소 사전 ```r useNIADic() ``` <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> `KoNLP` 패키지 설치 후 한 번만 실행 --- #### 형태소 분석기를 이용해 토큰화하기 - 명사 추출 ##### 샘플 텍스트로 작동 원리 알아보기 ```r library(KoNLP) library(dplyr) text <- tibble( value = c("대한민국은 민주공화국이다.", "대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.")) text ``` ``` ## # A tibble: 2 x 1 ## value ## <chr> ## 1 대한민국은 민주공화국이다. ## 2 대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다. ``` --- `extractNoun()`: 문장에서 추출한 명사를 list 구조로 출력 ```r extractNoun(text$value) ``` ``` ## [[1]] ## [1] "대한민국" "민주공화국" ## ## [[2]] ## [1] "대한민국" "주권" "국민" "권력" "국민" ``` <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> `extractNoun()`은 두 번째 실행부터 빠르게 작동 --- ##### `unnest_tokens()`를 이용해 명사 추출하기 - 다루기 쉬운 tibble 구조로 명사 출력 ```r library(tidytext) text %>% unnest_tokens(input = value, # 분석 대상 output = word, # 출력 변수명 * token = extractNoun) # 토큰화 함수 ``` ``` ## # A tibble: 7 x 1 ## word ## <chr> ## 1 대한민국 ## 2 민주공화국 ## 3 대한민국 ## 4 주권 ## 5 국민 ## 6 권력 ## 7 국민 ``` <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> `token` 파라미터에 입력한 `extractNoun` 앞뒤에 따옴표 X --- .pull-left[ ##### 띄어쓰기 기준 추출 ```r text %>% unnest_tokens(input = value, output = word, * token = "words") ``` ``` ## # A tibble: 10 x 1 ## word ## <chr> ## 1 대한민국은 ## 2 민주공화국이다 ## 3 대한민국의 ## 4 주권은 ## 5 국민에게 ## 6 있고 ## 7 모든 ## 8 권력은 ## 9 국민으로부터 ## 10 나온다 ``` ] .pull-right[ ##### 명사 추출 ```r text %>% unnest_tokens(input = value, output = word, * token = extractNoun) ``` ``` ## # A tibble: 7 x 1 ## word ## <chr> ## 1 대한민국 ## 2 민주공화국 ## 3 대한민국 ## 4 주권 ## 5 국민 ## 6 권력 ## 7 국민 ``` ] --- #### 연설문에서 명사 추출하기 ##### 문재인 대통령 연설문 불러오기 ```r raw_moon <- readLines("speech_moon.txt", encoding = "UTF-8") ``` ##### 기본적인 전처리 ```r library(stringr) moon <- raw_moon %>% str_replace_all("[^가-힣]", " ") %>% # 한글만 남기기 str_squish() %>% # 중복 공백 제거 as_tibble() # tibble로 변환 moon ``` --- ``` ## # A tibble: 117 x 1 ## value ## <chr> ## 1 "정권교체 하겠습니다" ## 2 "정치교체 하겠습니다" ## 3 "시대교체 하겠습니다" ## 4 "" ## 5 "불비불명 이라는 고사가 있습니다 남쪽 언덕 나뭇가지에 앉아 년 동안~ ## 6 "" ## 7 "그 동안 정치와 거리를 둬 왔습니다 그러나 암울한 시대가 저를 정치~ ## 8 "" ## 9 "" ## 10 "우리나라 대통령 이 되겠습니다" ## # ... with 107 more rows ``` --- ##### 명사 기준 토큰화 ```r word_noun <- moon %>% unnest_tokens(input = value, output = word, token = extractNoun) word_noun ``` ``` ## # A tibble: 1,757 x 1 ## word ## <chr> ## 1 "정권교체" ## 2 "하겠습니" ## 3 "정치" ## 4 "교체" ## 5 "하겠습니" ## 6 "시대" ## 7 "교체" ## 8 "하겠습니" ## 9 "" ## 10 "불비불명" ## # ... with 1,747 more rows ``` --- name: 02-2 class: title1 02-2 명사 빈도 분석하기 --- ##### 단어 빈도 구하기 - 빈도가 높은 명사를 보면 글쓴이가 무엇을 강조했는지 알 수 있음 - `# A tibble: 704 x 2`: 연설문이 704개의 명사로 구성됨 ```r word_noun <- word_noun %>% count(word, sort = T) %>% # 단어 빈도 구해 내림차순 정렬 filter(str_count(word) > 1) # 두 글자 이상만 남기기 word_noun ``` ``` ## # A tibble: 704 x 2 ## word n ## <chr> <int> ## 1 국민 21 ## 2 일자리 21 ## 3 나라 19 ## 4 우리 17 ## 5 경제 15 ## 6 사회 14 ## 7 성장 13 ## 8 대통령 12 ## 9 정치 12 ## 10 하게 12 ## # ... with 694 more rows ``` --- .pull-left[ ##### 띄어쓰기 기준 추출 ```r moon %>% unnest_tokens(input = value, output = word, * token = "words") %>% count(word, sort = T) %>% filter(str_count(word) > 1) ``` ``` ## # A tibble: 1,384 x 2 ## word n ## <chr> <int> ## 1 합니다 27 ## 2 있습니다 13 ## 3 저는 13 ## 4 있는 12 ## 5 함께 12 ## 6 만들겠습니다 11 ## 7 일자리 10 ## 8 국민의 9 ## 9 우리 9 ## 10 우리나라 9 ## # ... with 1,374 more rows ``` ] .pull-right[ ##### 명사 추출 ```r moon %>% unnest_tokens(input = value, output = word, * token = extractNoun) %>% count(word, sort = T) %>% filter(str_count(word) > 1) ``` ``` ## # A tibble: 704 x 2 ## word n ## <chr> <int> ## 1 국민 21 ## 2 일자리 21 ## 3 나라 19 ## 4 우리 17 ## 5 경제 15 ## 6 사회 14 ## 7 성장 13 ## 8 대통령 12 ## 9 정치 12 ## 10 하게 12 ## # ... with 694 more rows ``` ] --- ##### 막대 그래프 만들기 ```r # 상위 20개 단어 추출 top20 <- word_noun %>% head(20) ``` ```r # 막대 그래프 만들기 library(ggplot2) ggplot(top20, aes(x = reorder(word, n), y = n)) + geom_col() + coord_flip() + geom_text(aes(label = n), hjust = -0.3) + labs(x = NULL) + theme(text = element_text(family = "nanumgothic")) ``` --- - 명사로 되어있기 때문에 연설문의 내용을 이해하기 쉬움 <img src="02-morphologicalAnalysis_files/figure-html/unnamed-chunk-23-1.png" width="80%" /> --- <br> .pull-left[ ##### 띄어쓰기 기준 추출 <img src="Image/01/01_3_1.png" width="100%" /> ] .pull-right[ ##### 명사 추출 <img src="Image/02/01_2_1.png" width="100%" /> ] --- ##### 워드 클라우드 만들기 ```r # 폰트 설정 library(showtext) font_add_google(name = "Black Han Sans", family = "blackhansans") showtext_auto() library(ggwordcloud) ggplot(word_noun, aes(label = word, size = n, col = n)) + geom_text_wordcloud(seed = 1234, family = "blackhansans") + scale_radius(limits = c(3, NA), range = c(3, 15)) + scale_color_gradient(low = "#66aaf2", high = "#004EA1") + theme_minimal() ``` --- <br-back-50> <img src="Image/02/01_2_2.png" width="100%" /> --- <br> .pull-left[ ##### 띄어쓰기 기준 추출 <br-back-10> <img src="Image/01/01_3_6.png" width="90%" height="90%" /> ] .pull-right[ ##### 명사 추출 <br-back-20> <img src="Image/02/01_2_2.png" width="100%" /> ] --- name: 02-3 class: title1 02-3 특정 단어가 사용된 문장 살펴보기 --- - 고빈도 단어 사용된 문장 확인하기 - 글쓴이가 어떤 의미로 단어를 사용했는지 이해할 수 있음 -- ##### 문장 기준으로 토큰화하기 - 원문 `raw_moon`을 문장 기준으로 토큰화 ```r sentences_moon <- raw_moon %>% str_squish() %>% as_tibble() %>% unnest_tokens(input = value, output = sentence, * token = "sentences") sentences_moon ``` <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 --- ``` ## # A tibble: 207 x 1 ## sentence ## <chr> ## 1 정권교체 하겠습니다! ## 2 정치교체 하겠습니다! ## 3 시대교체 하겠습니다! ## 4 ‘불비불명(不飛不鳴)’이라는 고사가 있습니다. ## 5 남쪽 언덕 나뭇가지에 앉아, 3년 동안 날지도 울지도 않는 새. ## 6 그러나 그 새는 한번 날면 하늘 끝까지 날고, 한번 울면 천지를 뒤흔듭~ ## 7 그 동안 정치와 거리를 둬 왔습니다. ## 8 그러나 암울한 시대가 저를 정치로 불러냈습니다. ## 9 더 이상 남쪽 나뭇가지에 머무를 수 없었습니다. ## 10 이제 저는 국민과 함께 높이 날고 크게 울겠습니다. ## # ... with 197 more rows ``` --- #### 특정 단어가 사용된 문장 추출하기 ##### 특정 단어가 들어 있는지 확인하기 - `str_detect()` - 단어가 문장에 있으면 `TRUE`, 그렇지 않으면 `FALSE` 반환 ```r str_detect("치킨은 맛있다", "치킨") ``` ``` ## [1] TRUE ``` ```r str_detect("치킨은 맛있다", "피자") ``` ``` ## [1] FALSE ``` --- ##### 특정 단어가 사용된 문장 추출하기 .scroll-box-24[ ```r sentences_moon %>% filter(str_detect(sentence, "국민")) ``` ``` ## # A tibble: 19 x 1 ## sentence ## <chr> ## 1 이제 저는 국민과 함께 높이 날고 크게 울겠습니다. ## 2 오늘 저는 제18대 대통령선거 출마를 국민 앞에 엄숙히 선언합니다. ## 3 존경하는 국민 여러분! ## 4 국민이 모두 아픕니다. ## 5 국민 한 사람 한 사람이 모두 아픕니다. ## 6 국민들에게 희망을 주는 정치가 절실하게 필요합니다. ## 7 국민의 뜻이 대통령의 길입니다. ## 8 저는 대선출마를 결심하고 국민 여러분께 출마선언문을 함께 쓰자고 제~ ## 9 시민의 한숨과 눈물을 닦아주지 못하는 정치가 있었고, 오히려 국민의 ~ ## 10 상식이 통하는 사회, 권한과 책임이 비례하는 사회, 다름을 인정하는 ~ ## 11 그러나 거창하게만 들리는 이 국가비전 역시 국민의 마음속에 있었습니~ ## 12 더욱 낮아지고 겸손해져서 국민의 마음속으로 들어가라. ## 13 국민들이 제게 준 가르침입니다. ## 14 국민의 뜻에서 대통령의 길을 찾겠습니다. ## 15 문화혁신을 통해 모든 국민의 창조성을 높이고 이를 통해 기술혁신과 ~ ## 16 이렇게 하면 국민의 살림이 서서히 나아질 것이며 5년 뒤에는 큰 성과~ ## 17 이명박 정부의 방해에도 불구하고 끝내 국민이 지켜준 세종시, 혁신도~ ## 18 존경하는 국민 여러분! ## 19 국민의 마음에서 길을 찾는 우리나라 대통령이 되겠습니다. ``` ] --- ##### 특정 단어가 사용된 문장 추출하기 .scroll-box-24[ ```r sentences_moon %>% filter(str_detect(sentence, "일자리")) ``` ``` ## # A tibble: 18 x 1 ## sentence ## <chr> ## 1 빚 갚기 힘들어서, 아이 키우기 힘들어서, 일자리가 보이지 않아서 아~ ## 2 상생과 평화의 대한민국은 공평과 정의에 바탕을 두고, 성장의 과실을 ~ ## 3 복지의 확대를 통해 보육, 교육, 의료, 요양 등 사회서비스 부문에 수~ ## 4 결국 복지국가로 가는 길은 사람에 대한 투자, 일자리 창출, 자영업 고~ ## 5 ‘일자리 정부’로 ‘일자리 혁명’을 이루겠습니다. ## 6 복지의 확대와 함께 저는 강력한 ‘일자리 혁명’을 이루고자 합니다. ## 7 지금 너무나 많은 젊은이들과 실업자, 비정규직 종사자, 근로능력이 있~ ## 8 좋은 일자리 창출을 위해 비정규직의 정규직 전환 촉진, 비정규직에 대~ ## 9 또한 정보통신 산업, 바이오산업, 나노 산업, 신재생에너지 산업, 문화~ ## 10 그리고 앞에서 말한 보육, 교육, 의료, 복지 등 사회서비스 부문은 무~ ## 11 일자리 없는 곳에서 희망을 찾을 수 없습니다. ## 12 지방 일자리에 대해 특별한 노력을 기울이겠습니다. ## 13 지역균형발전은 곧 산업 균형, 일자리 균형이 목표입니다. ## 14 이명박 정부의 방해에도 불구하고 끝내 국민이 지켜준 세종시, 혁신도~ ## 15 이 모든 정책의 실효성을 담보하기 위해 대통령이 되면 저는 가장 먼저~ ## 16 저는 먼 훗날 ‘일자리 혁명을 일으킨 대통령’으로 평가받기를 희망합~ ## 17 또한 좋은 일자리와 산업혁신을 위해서는 평생학습체제가 뒷받침되어야~ ## 18 노인 일자리를 늘리고, 특히 그 연륜과 경험을 지역사회에 활용할 수 ~ ``` ] --- <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> tibble 구조는 텍스트가 길면 Console 창 크기에 맞춰 일부만 출력함 - 모든 내용 출력 하려면: `%>% data.frame()` - 왼쪽 정렬 출력 하려면: `%>% print.data.frame(right = F)` --- .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> 형태소 분석기의 한계] - 분석 결과에 '하게' 처럼 의미를 알 수 없는 단어가 들어 있음 - 형태소 사전에 '하게'라는 명사가 있음 - '당당하게', '절실하게' 등의 '하게'를 명사로 분류해 생긴 오류 - 형태소 분석기의 성능에 한계가 있기 때문에 분석하면서 오류를 찾아 수정해야 함 ] --- class: title1 정리하기 --- <br-back-10> ### 정리하기 ##### 1. 명사 추출하기 ```r # 명사 기준 토큰화 word_noun <- moon %>% unnest_tokens(input = value, output = word, token = extractNoun) ``` <br-back-10> ##### 2. 특정 단어가 사용된 문장 살펴보기 ```r # 문장 기준 토큰화 sentences_moon <- raw_moon %>% str_squish() %>% as_tibble() %>% unnest_tokens(input = value, output = sentence, token = "sentences") # 특정 단어가 사용된 문장 추출 sentences_moon %>% filter(str_detect(sentence, "국민")) ``` --- class: title1 분석 도전 --- ### 분석 도전 박근혜 전 대통령의 대선 출마 선언문이 들어있는 `speech_park.txt`를 이용해 문제를 해결해 보세요. Q1. `speech_park.txt`를 불러와 분석에 적합하게 전처리한 다음 연설문에서 명사를 추출하세요. Q2. 가장 자주 사용된 단어 20개를 추출하세요. Q3. 가장 자주 사용된 단어 20개의 빈도를 나타낸 막대 그래프를 만드세요. Q4. 전처리하지 않은 연설문에서 연속된 공백을 제거하고 tibble 구조로 변환한 다음 <br> 문장 기준으로 토큰화하세요. Q5. 연설문에서 `"경제"`가 사용된 문장을 출력하세요. --- Q1. `speech_park.txt`를 불러와 분석에 적합하게 전처리한 다음 연설문에서 명사를 추출하세요. ```r raw_park <- readLines("speech_park.txt", encoding = "UTF-8") # 전처리 library(dplyr) library(stringr) park <- raw_park %>% str_replace_all("[^가-힣]", " ") %>% # 한글만 남기기 str_squish() %>% # 연속된 공백 제거 as_tibble() # tibble로 변환 park ``` --- Q1. `speech_park.txt`를 불러와 분석에 적합하게 전처리한 다음 연설문에서 명사를 추출하세요. ``` ## # A tibble: 96 x 1 ## value ## <chr> ## 1 "존경하는 국민 여러분 저는 오늘 국민 한 분 한 분의 꿈이 이루어지는~ ## 2 "" ## 3 "국민 여러분 저의 삶은 대한민국과 함께 해온 시간이었습니다 우리나~ ## 4 "" ## 5 "어머니가 흉탄에 돌아가신 후 견딜 수 없는 고통과 어려움 속에서도 ~ ## 6 "" ## 7 "그때부터 제 삶은 완전히 다른 길을 가야했습니다 개인의 삶 대신 국~ ## 8 "" ## 9 "아버지를 잃는 또 다른 고통과 아픔을 겪고 저는 평범한 삶을 살고자 ~ ## 10 "" ## # ... with 86 more rows ``` --- Q1. `speech_park.txt`를 불러와 분석에 적합하게 전처리한 다음 연설문에서 명사를 추출하세요. .scroll-box-26[ ```r # 명사 기준 토큰화 library(tidytext) library(KoNLP) word_noun <- park %>% unnest_tokens(input = value, output = word, token = extractNoun) word_noun ``` ``` ## # A tibble: 1,240 x 1 ## word ## <chr> ## 1 존경 ## 2 하 ## 3 국민 ## 4 여러분 ## 5 저 ## 6 오늘 ## 7 국민 ## 8 한 ## 9 분 ## 10 한 ## # ... with 1,230 more rows ``` ] --- Q2. 가장 자주 사용된 단어 20개를 추출하세요. .scroll-box-26[ ```r top20 <- word_noun %>% count(word, sort = T) %>% filter(str_count(word) > 1) %>% head(20) top20 ``` ``` ## # A tibble: 20 x 2 ## word n ## <chr> <int> ## 1 국민 72 ## 2 행복 23 ## 3 여러분 20 ## 4 정부 17 ## 5 경제 15 ## 6 신뢰 11 ## 7 국가 10 ## 8 우리 10 ## 9 교육 9 ## 10 사람 9 ## 11 사회 9 ## 12 일자리 9 ## 13 박근혜 8 ## 14 불안 8 ## 15 대한민국 6 ## 16 발전 6 ## 17 중요 6 ## 18 하게 6 ## 19 공유 5 ## 20 노력 5 ``` ] --- Q3. 가장 자주 사용된 단어 20개의 빈도를 나타낸 막대 그래프를 만드세요. ```r library(ggplot2) ggplot(top20, aes(x = reorder(word, n), y = n)) + geom_col() + coord_flip () + geom_text(aes(label = n), hjust = -0.3) + labs(x = NULL) ``` --- <img src="02-morphologicalAnalysis_files/figure-html/unnamed-chunk-42-1.png" width="100%" /> --- Q4. 전처리하지 않은 연설문에서 연속된 공백을 제거하고 tibble 구조로 변환한 다음 <br> 문장 기준으로 토큰화하세요. .scroll-box-26[ ```r sentences_park <- raw_park %>% str_squish() %>% # 연속된 공백 제거 as_tibble() %>% # tibble로 변환 unnest_tokens(input = value, output = sentence, token = "sentences") sentences_park ``` ``` ## # A tibble: 119 x 1 ## sentence ## <chr> ## 1 존경하는 국민 여러분! ## 2 저는 오늘, 국민 한 분 한 분의 꿈이 이루어지는 행복한 대한민국을 만~ ## 3 저 박근혜, 이번 18대 대통령선거 출마를 선언합니다. ## 4 국민 여러분! ## 5 저의 삶은 대한민국과 함께 해온 시간이었습니다. ## 6 우리나라가 가난을 이기고, 꿈을 이뤄가는 위대한 과정을 어린 시절부~ ## 7 어머니가 흉탄에 돌아가신 후, 견딜 수 없는 고통과 어려움 속에서도 ~ ## 8 그리고 늘 함께 해주시고 힘이 되어 주셨던 국민 여러분이 계셨기 때문~ ## 9 제가 그 막중한 일을 해내고, 고통을 이겨내고 다시 일어설 수 있었던 ~ ## 10 그때부터 제 삶은 완전히 다른 길을 가야했습니다. ## # ... with 109 more rows ``` ] --- Q5. 연설문에서 `"경제"`가 사용된 문장을 출력하세요. .scroll-box-26[ ```r sentences_park %>% filter(str_detect(sentence, "경제")) ``` ``` ## # A tibble: 11 x 1 ## sentence ## <chr> ## 1 국가는 발전했고, 경제는 성장했다는데, 나의 삶은 나아지지 않았고, ~ ## 2 저는 ‘경제민주화 실현’, ‘일자리 창출’, 그리고 ‘한국형 복지의 ~ ## 3 국민행복의 길을 열어갈 첫 번째 과제로, 저는 경제민주화를 통해 중소~ ## 4 그동안 우리 경제는 효율성을 지나치게 강조하면서 공정성의 중요성을 ~ ## 5 공정하고 투명한 시장경제 질서를 확립해 경제민주화를 실현하는 일은 ~ ## 6 정당한 기업활동은 최대한 보장하고 불필요한 규제는 철폐하여 경제에 ~ ## 7 수출 일변도의 경제구조에서 벗어나 수출과 내수가 동시에 성장을 견인~ ## 8 복지가 국민 개개인이 가진 자기 역량을 뒷받침하고 끌어내서 자립·자~ ## 9 국민 여러분, 올해는 우리나라 경제발전의 틀을 마련한 경제개발 5개년~ ## 10 저는 국민행복을 위해 ‘경제민주화-일자리-복지’를 아우르는 (가칭)~ ## 11 50년 전 경제개발 5개년 계획이 산업화의 기적을 이뤄냈듯,‘오천만 국~ ``` ] --- class: title0 끝