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

  • 텍스트 전처리에 사용할 패키지를 불러옵니다.
pacman::p_load('tidymodels','tidytext','NLP4kec' ,'stringr','magrittr','tm', 'network','GGally', 'sna', 'RColorBrewer)
  • 이제 지난 시간에 만들었던 dtmTfIdf 를 활용하여 단어네트워크맵을 그려보겠습니다.

12.1 네트워크 객체 추출

  • 지난 chapter에서 만들어 두었던 dtmTfIdf 와 corTerms가 제대로 준비되어 있는지 확인합니다. 네트워크맵을 그리기 위해 dimension을 축소했었는데, 잘 반영되어 있는지도 확인해줍니다.
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)
corTerms[1:10,1:10]
##                  가능         가다         가족      가지다        갈다
## 가능      1.000000000 -0.027104290 -0.023975472 -0.02148840 -0.02554500
## 가다     -0.027104290  1.000000000  0.017125433 -0.01015356 -0.01569470
## 가족     -0.023975472  0.017125433  1.000000000 -0.01711972 -0.01172670
## 가지다   -0.021488399 -0.010153557 -0.017119722  1.00000000 -0.01724621
## 갈다     -0.025545004 -0.015694705 -0.011726696 -0.01724621  1.00000000
## 강도     -0.047184333 -0.006153643 -0.020628759 -0.02827727 -0.02280550
## 강력하다 -0.019741898 -0.001551922 -0.010230558 -0.01504587 -0.01030615
## 강성     -0.015395833 -0.016097999  0.028548568 -0.01768937 -0.01211690
## 강하다    0.007669403 -0.018389782 -0.009818242 -0.02020771  0.02640818
## 갖추다   -0.018864374 -0.014450486 -0.010797046 -0.01587900 -0.01087682
##                  강도     강력하다        강성       강하다       갖추다
## 가능     -0.047184333 -0.019741898 -0.01539583  0.007669403 -0.018864374
## 가다     -0.006153643 -0.001551922 -0.01609800 -0.018389782 -0.014450486
## 가족     -0.020628759 -0.010230558  0.02854857 -0.009818242 -0.010797046
## 가지다   -0.028277273 -0.015045873 -0.01768937 -0.020207712 -0.015878996
## 갈다     -0.022805500 -0.010306147 -0.01211690  0.026408179 -0.010876821
## 강도      1.000000000 -0.019895885 -0.02339151  0.105853061 -0.001332071
## 강력하다 -0.019895885  1.000000000 -0.01057098 -0.012075907 -0.009489113
## 강성     -0.023391514 -0.010570976  1.00000000 -0.014197597 -0.011156314
## 강하다    0.105853061 -0.012075907 -0.01419760  1.000000000 -0.012744576
## 갖추다   -0.001332071 -0.009489113 -0.01115631 -0.012744576  1.000000000
dim(corTerms) 
## [1] 209 209
  • 잘 반영되어 있음이 확인되었고, 이제 네트워크 맵을 그리기 위한 패키지를 확인해봅니다. network 패키지, GGally 패키지를 주로 사용할 예정입니다.

  • network 패키지를 사용하여 network analysis를 하고, network map을 그리기 위한 객체를 완성합니다. 해당 객체는 기본 plot으로도 그려지지만, 보다 알아보기 쉽게 표현하기 위해 GGally 패키지를 활용하여 네트워크 맵을 그립니다.

구분 내용 활용 패키지
network 분석 TF-IDF를 활용하여 구한 단어간 상관관계 데이터 기반으로 network analysis를 진행합니다 network
network개체 생성 network analysis를 통해 매개중심성 등을 계산하여 network 개체를 생성합니다. network
네트워크맵 그리기 network 객체를 GGally 패키지를 통해 시각화 합니다 GGally

12.1.1 corTerms to network obj

  netTerms <- network(x = corTerms, directed = FALSE)
  • network 객체는 network 함수에 넣어 주면 바로 생성이 됩니다.

  • 결과를 살펴보면, vertices 는 209개이고, edge는 21,736개 임을 알 수 있습니다. 앞서 corTerms의 Dimeson 이 209 x 209임을 확인했습니다. 이는 209개의 단어들의 상관행렬이며, network 객체는 이 상관행렬을 기반으로 209개의 단어들의 관계를 21,736개의 선(edge)로 이어준 것임을 알 수 있습니다.

  • network 함수에는 다양한 인자들이 있으며, 각각의 이곳을 참고하시면 됩니다.

  • 이렇게 구한 network 객체를 plot 함수로 바로 그려볼 수도 있습니다.

plot(netTerms, vertex.cex = 1)

  • network 객체를 그대로 그리면, 위와 같이 동그란 구가 보이실 것입니다. 21,736개의 선이 209개의 단어를 연결해주고 있다보니, 그냥 원처럼 보이는 것입니다.

  • 효과적으로, 정말 중요한 네트워크를 분석하기 위해서는 상관행렬의 크기를 조정해서 edge 개수를 줄이고, 중심성을 계산해줘야 합니다. 중심성은 크게 세가지를 기억해주시면 됩니다.

구분 내용
Degree Centrality (연결 중심성) 네트워크의 한 노드가 몇 개의 노드와 직접 연결되어 있는지 측정
Closeness Centrality (근접 중심성) 네트워크의 노드간 직접연결 뿐 아니라 간접 연결까지 포함해서 중심성을 측정
Betweeness Centrality (매개 중심성) 네트워크의 노드가 중계자(브로커) 역할을 얼마나 잘하는지 측정
  • 저는 단어와 단어들을 연결해주는 중계자 역할을 하는 노드를 눈여겨 보기 때문에 매개중심성을 활용하여 네트워크맵을 그리는 편입니다.

12.1.2 상관행렬 크기 조정

corTerms[corTerms <= 0.15] <- 0
netTerms <- network(x = corTerms, directed = FALSE)
netTerms
##  Network attributes:
##   vertices = 209 
##   directed = FALSE 
##   hyper = FALSE 
##   loops = FALSE 
##   multiple = FALSE 
##   bipartite = FALSE 
##   total edges= 182 
##     missing edges= 0 
##     non-missing edges= 182 
## 
##  Vertex attribute names: 
##     vertex.names 
## 
## No edge attributes
  • 상관계수가 0.15보다 작은 값들을 모두 0으로 만들어주니, edge의 개수가 21,736개에서 182개로 확 줄어든 것을 확인하실 수 있습니다.

  • 이제 다시 기본 플랏을 그려보겠습니다.

plot(netTerms, vertex.cex = 1)

  • 상관행렬 차원을 축소하기 전에는 하나의 커다란 구로 보였는데, 이제는 어느 정도 네트워크맵처럼 생긴 것 같아 보입니다.

  • 상관행렬의 기준이 되는 상관계수를 결정해주는 것은 매우 중요합니다.

  • 저는 0.5부터 0.2까지 넣어서 해보았고, 상관계수에 따라 그려지는 네트워크맵을 보면서 가장 적합한 모양을 찾아 결정했습니다.

상관행렬 축소에 따른 네트워크맵

  • 네트워크맵을 그리실 때는 위와 같은 과정을 거쳐서, 가장 적합한 상관계수를 정해주시면 좋습니다.
  • 네트워크맵에 대해 완벽하게 이해하신 후에는 상관계수를 인수로 하여 그때 그때 바꿔가며 그림을 그려주는 함수를 만들어줄 수도 있습니다.

12.2 매개 중심성 계산

  • sna 패키지의 betweenness 함수를 활용하면 매개중심성을 구할 수 있습니다.
  • 매개중심성을 구하고, 10행까지만 살펴보면 아래와 같습니다.
btnTerms <- betweenness(netTerms) 
btnTerms[1:10]
##  [1]    2.000    0.000  234.000  234.000 2661.400 1368.400    0.000 2439.267
##  [9]    0.000  234.000

12.3 네트워크 맵 그리기

  • 이제 GGally 패키지를 활용하여 네트워크맵을 그려보겠습니다.
  • 네트워크 맵을 그릴 때 고려해야 하는 것들도 매우 많은데, 추가 옵션들은 ggnet vignette을 참고해주시면 감사하겠습니다.
  • 이 곳에서는 가장 기본적인 내용만 다루고 넘어가도록 하겠습니다.
  • 간편하게 다른 분이 작성한 코드를 활용하기 원하신다면 나승호님 블로그를 참고해주시면 됩니다.

12.3.1 매개중심성 표현

  • 네트워크 맵을 그리기에 앞서, 어떤 노드가 중요한 노드인지 표현해주기 위해, 매개중심성 기준 중요성 상위 10%는 금색, 나머지는 흰색으로 표현해보겠습니다.
# netTerms에서 매개중심성(btnTerms)가 10% 이상인 경우, Top을 붙여주고, 
# 그 외에는 Rest를 붙여줍니다. 

# %v% 는 %vattr% (Vertex attribute)의 약자로 꼭지점의 속성을 추가할 때 
# 사용하는 함수 set.vertex.attribute(x,attrname,value)과 동일한 기능을 수행합니다. 

# netTerms의 vertex에 mode라는 attribute를 추가하고, 매개중심성 상위 10%에 Top, 
# 나머지는 Rest라는 속성을 추가하는 함수입니다. 

 netTerms %v% 'mode' <-
    ifelse(
      test = btnTerms >= quantile(x = btnTerms, probs = 0.90, na.rm = TRUE), 
      yes = 'Top', 
      no = 'Rest')


nodeColors <- c('Top' = 'gold', 'Rest' = 'lightgrey')

12.3.2 엣지 크기 설정

  • 엣지 크기는 곧 선의 굵기 입니다.
  • 선의 굵기를 상관계수가 클수록 굵게 설정하여 노드간에 얼마나 강한 연결관계가 있는지 쉽게 확인합니다.
# edge의 크기를 상관계수의 3배로 설정을 해보겠습니다. 

set.edge.value(netTerms, attrname = 'edgeSize', value = corTerms * 3)

12.3.3 네트워크 맵 그리기(1)

  • 상관계수에 따라 엣지의 크기를 조절해주어야 단어 간의 관계가 좀 더 명확하게 보입니다.
  • 매개중심성을 반영하지 않은 상태에서 네트워크맵을 그리면 아래와 같습니다.
  • ggnet함수를 통해 네트워크맵을 그리는 옵션에 대해서는 (ggnet2 vignette)[https://briatte.github.io/ggnet/]를 참조 부탁드리며, R Tips 중급자 편에서 조금 더 자세히 다루도록 하겠습니다.
ggnet2(
    net = netTerms,
    size.min = 3,
    label = TRUE,
    label.size = 3,
    node.size = sna::degree(dat = netTerms),
    edge.size = 'edgeSize',
    family = 'AppleGothic')+
    theme(plot.title = element_text(hjust = 0.5, face = 'bold')
          
      )

12.3.4 네트워크 맵 그리기(2)

  • 이제 앞서 구한 매개중심성을 반영하여, 상위 10% 노드만 노란색으로 표시되게 해보겠습니다.
ggnet2(
    net = netTerms,
    mode = 'fruchtermanreingold',
    layout.par = list(cell.jitter = 0.001),
    size.min = 3,
    label = TRUE,
    label.size = 3,
    node.color = 'mode',
    palette = nodeColors,
    node.size = sna::degree(dat = netTerms),
    edge.size = 'edgeSize',
    family = 'AppleGothic')+
    labs(title = "매개중심성 반영한 단어-네트워크맵")+  
    theme_gray(base_family = 'NanumGothic') # 이 부분은 Mac 사용자만!

* 매개중심성이 상위 10%인 노드만 눈에 띄게 하니 더 보기 쉬워졌습니다.
* 상위 노드를 중심으로 현대자동차의 장점 단어-네트워크맵 결과를 정리해보면 아래와 같습니다.

구분 네트워크 의미 분석
1 동종-글로벌-자동차-업계-자부심 동종 자동차업계중 글로벌 업체라는 자부심
2 자유-연월차-사용 연월차 사용이 자유롭다
3 노조-강성-정년-보장 노조가 강성이라 정년이 보장된다
4 시간-출근-주말-없다 주말에 출근하는 일이 없다
5 업무-본사-해외-경험-쌓다-다양하다-기회 해외 및 다양한 업무 경험을 쌓을 수 있다
  • 초반에 텍스트에 대해 전처리를 조금 더 했다면, 더 보기 좋게 나왔을것입니다.

  • 예를들어, 연차, 월차, 휴가, 연월차 등 동일한 의미를 가진 단어를 합쳐주었다면 훨씬 보기 좋은 단어-네트워크맵이 나왔을 것입니다. 아울러, 조직에 대한 배경지식이 있다면 연관된 단어를 보고 어떤 의미인지 떠올리기 더 쉬우실 것입니다.

  • 이렇게 간단하게 단어-네트워크맵을 구성하여, 주관식 텍스트를 파악하실 수 있습니다.