Chapter 11 텍스트 데이터-단어 네트워크맵(1)

  • 텍스트 전처리에 사용할 패키지를 불러옵니다.
pacman::p_load('tidymodels','tidytext','NLP4kec' ,'stringr','magrittr','tm')

11.1 DTM by TFIDF

  • chapter 10 텍스트 분석에서 단어 상관 행렬을 만들었지만, 가중치를 Term Frequency로 했습니다.

  • 이번에는 TF-IDF 가중치를 활용하여 DTM을 만들어서 활용하겠습니다.

  • 지난 시간 DTM을 만들 때 활용했던 동일한 함수를 사용하지만, control 인자에 TFidf를 가중치로 주었고, 숫자로 된 단어를 제외하고 2글자 이상 단어만 사용해서 DTM을 만들어보았습니다.

dtmTfIdf <- DocumentTermMatrix( x = corp, control = list( removeNumbers = TRUE, wordLengths = c(2, Inf), weighting = function(x) weightTfIdf(x, normalize = TRUE) ))  
dtmTfIdf
## <<DocumentTermMatrix (documents: 1214, terms: 2014)>>
## Non-/sparse entries: 14538/2430458
## Sparsity           : 99%
## Maximal term length: 6
## Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)
  • dtmTFidf 의 정보를 간략하게 보면 아래와 같습니다.
<<DocumentTermMatrix (documents: 1214, terms: 1901)>>
Non-/sparse entries: 14523/2293291
Sparsity           : 99%
Maximal term length: 6
Weighting          : term frequency - inverse document frequency (normalized) 
  • 1214개의 문서에 X 1,901개 단어 는 2,307,814 칸으로 구성된 DTM을 만든다는 것을 알 수 있습니다.

  • 만들어진 DTM은 1,214개의 문서와 1,901개의 단어 조합으로 이루어졌습니다.
    이 조합은 1,214 X 1,901 = 2,307,814개의 값으로 이루어졌다고 보시면 됩니다.

  • Non-/sparse entires는 전체 값 2,307,814개 중 0이 아닌 값이 14,523개 있고, 0인 값이 2,293,291개 있다는 의미입니다. 0이 많은 자료를 희소성(Saprsity)이 있는 자료라고 하며, 네트워크 이론에서 유용하게 활용됩니다. sparsity는 전체 행렬에서 0이 차지하는 비중을 의미합니다.

  • Maximal term Length는 가장 긴 단어의 경우 6글자로 이루어졌다는 것이며, 가중치는 Normalized tf-idf로 주었다고 보시면 됩니다.

  • tf-idf 앞에 Normalize 가 붙는 이유는, tf(term-frequency)가 무한대로 발산할 수도 있기 때문입니다. 자세한 내용은 아래 링크 참조 부탁드리며, weigthTfIdf함수는 정규화 방법으로 Boolean frequency 방법을 사용합니다.

    TF-IDF 설명 링크

11.2 dtm 차원 축소

removeSparseTerms(dtm, sparse 기준)

  • 단어-네트워크 맵을 만들 때는 dtm의 차원을 줄여주는 것이 좋습니다.

  • 차원을 줄여주는 이유는 텍스트 데이터의 차원이 매우 높아, 차원의 저주가 존재하기 때문인데, 더 자세한 내용은 링크나 첨부드린 한국은행에서 발간한 “경제 분석을 위한 텍스트마이닝” 자료를 참고하시면 좋을 것 같습니다.

  • 이제, 작업의 편의를 위해 대부분이 0 값을 가진 것으로 판단할 수 있는 Sparsity 가 0.99가 넘는 열을 삭제해줍니다.

dim(dtmTfIdf)
## [1] 1214 2014
dtmTfIdf <- removeSparseTerms(x =  dtmTfIdf, sparse = as.numeric(x = 0.99))
# removeSparseTerms 함수를 활용해서 dtmTfIdf에 sparse가 0.99를 넘는 열을 삭제하고, 그것을 다시 dtmTfIdf 로 만들어 달라 는 뜻입니다.  
  
dtmTfIdf
## <<DocumentTermMatrix (documents: 1214, terms: 209)>>
## Non-/sparse entries: 10221/243505
## Sparsity           : 96%
## Maximal term length: 4
## Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)
# Sparsity가 0.99가 넘는 열을 삭제하니, term이 213개만 남은 것을 알 수 있습니다.

11.3 키워드 상관 단어 파악

  • 이제 차원이 축소된 dtmTfIdf 가 완성되었고, 내가 원하는 단어와 상관관계가 있는 단어가 무엇인지 findAssocs 함수를 통해 확인해보실 수 있습니다.

findAssocs(x, terms, corlimit)

  • 위 함수에 x에는 dtm을 넣으시고, terms에는 원하는 단어, corlimit는 상관계수 몇 이상의 단어를 볼 것인지 넣어주시면 됩니다.
findAssocs(dtmTfIdf,'조직',0.1)
## $조직
## 빠르다 수요일 따르다   문화   직장 칼퇴근 
##   0.20   0.16   0.14   0.13   0.11   0.11
findAssocs(dtmTfIdf,'문화',0.1)
## $문화
## 군대 사내 개선 조직 지다 
## 0.25 0.18 0.13 0.13 0.10
  • ’조직’과 관련되어 있는 단어 중 상관계수 0.1 이상인 단어를 보여달라고 하니, 빠르다 라는 동사가 상관계수 0.2로 나왔고, 총 5개의 단어가 나왔습니다.

  • 아예 상관행렬을 만들어서, 내가 원하는 키워드와 상관이 있는 단어를 순위대로 보실 수도 있습니다.

11.4 상관행렬 만들기

dtmTfIdf %>% as.matrix() %>% cor() -> corTerms

  • dtmTfIdf를 매트릭스로 바꿔서 상관계수를 구하는 함수에 넣고, 그 결과를 corTerms로 저장하라는 뜻입니다.

  • 이제 지난 시간에 만든 것처럼, 앞서 만든 dtmTfIdf 를 가지고 단어간 상관행렬을 만들어줍니다.

dtmTfIdf %>% as.matrix() %>% cor() -> corTerms
glimpse(corTerms)
##  num [1:209, 1:209] 1 -0.0271 -0.024 -0.0215 -0.0255 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:209] "가능" "가다" "가족" "가지다" ...
##   ..$ : chr [1:209] "가능" "가다" "가족" "가지다" ...
  • 만들어진 단어간 상관행렬 CorTerms를 보시면, 속성(attribute)에 단어들이 들어가있고, 상관계수가 값으로 들어가 있습니다.

11.5 상관 단어 추출

  • 만들어진 상관행렬 CorTerms를 활용하여 특정 단어와 연관된 단어를 추출하는 함수를 작성해보겠습니다.

  • 단어를 입력 받아서, 연관된 단어 10개를 출력하는 함수를 제가 애정하는 나승호님 블로그에서 가져와 봤습니다.

# 키워드 유무를 확인합니다.
checkCorTerms <- function(x,n = 10, keyword) {
   
   # 키워드 유무를 확인합니다.
   x %>%
     colnames() %>%
     str_subset(pattern = keyword) %>%
     print()
   
   # 연관 키워드가 있는 컬럼의 전체 단어를 한꺼번에 출력합니다.
   corRef <- data.frame()
   
   # 상관계수 높은 순서로 정렬합니다.
   corRef <- x[ , keyword] %>%
     sort(decreasing = TRUE) %>%
     data.frame() %>%
     set_colnames(c('corr'))
   
   # 미리보기 합니다.
   head(x = corRef, n = n + 1)
 }
 
checkCorTerms(corTerms, 10 ,'문화')
## [1] "문화"
##              corr
## 문화   1.00000000
## 군대   0.24615889
## 사내   0.17608346
## 개선   0.13350531
## 조직   0.12682384
## 지다   0.10053374
## 나름   0.09829893
## 발전   0.08455702
## 기업   0.08285898
## 않다   0.06274883
## 보이다 0.06063198
  • CheckCorTerms() 함수로 문화와 상관관계가 있는 단어 10개를 보니, 앞서 FindAssocs 함수로 확인한 결과와 동일하게 나옵니다.

  • 이제 단어-네트워크맵을 그리기 위한 사전 준비가 마무리되었습니다.