聰明不如鈍筆
총명불여둔필
assignment KindeR

ggplot 스타일로 낱말구름 그리기(feat. ggwordcloud)


왜 이 생각을 못했을까요?


ggplot() 문법으로 사회연결망을 그릴 수 있는 ggraph가 있으면 당연히 같은 방식으로 낱말구름(워드클라우드)을 그리도록 도와주는 패키지도 있는 게 당연한 일이었는데 말입니다.


여태 이걸 모르고 '최대한 친절하게 쓴 R로 낱말구름, 의미연결망 그리기(feat. tidyverse, KoNLP)' 포스트에서도 열심히 wordcloud2 패키지만 설명했습니다.


그리하여 오늘 우리가 가지고 놀 장난감은 ggwordcloud 패키지 되겠습니다.


처음 '이런 패키지가 있지 않을까'하고 의심을 품게 된 건 페이스북 R 스터디 그룹에 올라온 아래 게시물을 보게 됐기 때문.


안녕하세요?


자연어처리관련해서 질문드립니다.


(**결정적인 도움을 주신 분(들)께 스타벅스 커피를 보내드립니다.)


목표로 하는 자연어의 전처리를 모두 완료한 ceo_message_tidy_filtered라는 리스트가 있습니다.


첨부에 나와있듯이 ceo_message_tidy_filtered로부터 2019년 hot keyword랑 2018년 hot keyword를 추출하였습니다. 그런데, 2018년 2019년간의 hot keyword의 변화를 보여주기 위해서, comparision.cloud를 이용해서 cloud 그래프를 보여주고 싶은데, ceo_message_tidy_filtered을 어떻게 처리해야 할 지 모르겠네요...


https://statkclee.github.io/text/nlp-amazon-google.html 를 참조했지만, 스스로 만드는 코드에 진전이 없습니다.조언 부탁드립니다.



일단 그림에 나온 자료를 담은 CSV 파일을 하나 만들었습니다. 작업을 따라 진행해 보고 싶으시면 내려 받으셔서 불러오시면 됩니다.


message.csv


이 파일 내용을 m이라는 변수에 넣은 다음 작업을 진행하도록 하겠습니다.


아, 저는 R로 작업할 때는 항상 tidyverse 패키지를 불러오는 걸로 시작합니다. 그리고 물론 당연히 ggwordcloud 패키지도 불러와야겠죠?

library('tidyverse')
## Registered S3 methods overwritten by 'ggplot2':
##   method         from 
##   [.quosures     rlang
##   c.quosures     rlang
##   print.quosures rlang
## -- Attaching packages ---------------------------------------------------------------- tidyverse 1.2.1 --
## √ ggplot2 3.1.1     √ purrr   0.3.2
## √ tibble  2.1.3     √ dplyr   0.8.1
## √ tidyr   0.8.3     √ stringr 1.4.0
## √ readr   1.3.1     √ forcats 0.3.0
## -- Conflicts ------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
#install.packages('ggwordcloud')
library('ggwordcloud')
m <- read.csv('message.csv')
m %>% head
##   year   corpus   n
## 1 2018       5g 182
## 2 2018 customer 157
## 3 2018 ericsson 132
## 4 2018 business 121
## 5 2018     work  95
## 6 2018     make  90


자료 정리가 끝났으니 첫 번째 낱말구름을 그려보겠습니다.


그냥 ggplot() 문법에 맞게 코드를 쓰시면 됩니다. 낱말구름을 그리는 함수는 geom_text_area()입니다. 

ggplot(m, aes(label=corpus, size=n)) + 
    geom_text_wordcloud_area()


글씨가 작네요. 이럴 때는 scale_size_area() 함수 안에 max_size 속성을 수정해 주시면 됩니다. 저는 최고 크기를 14로 키우겠습니다.

ggplot(m, aes(label=corpus, size=n)) + 
    geom_text_wordcloud_area() +
    scale_size_area(max_size=14) 


ggplot() 문법을 쓸 수 있다는 건 연도에 따라 글자 색깔을 구분하거나 facet_grid() 또는 facet_wrap()을 써서 낱말구름을 나눠 그릴 수도 있다는 뜻.


한 번 연도에 따라 글씨 색깔도 바꾸고 위·아래로 facet도 나눠 보겠습니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year))) + 
    geom_text_wordcloud_area() +
    scale_size_area(max_size=14) +
    facet_grid(year~.)


높이가 줄어들다 보니까 낱말구름이 옆으로 퍼진 감이 듭니다.


이 폭을 좁히고 싶을 때는 geom_text_wordcloud_area() 안에 eccentricity 속성을 조절하면 된다고 ggwordcloud 패키지 설명서에 나와 있습니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year))) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    facet_grid(year~.)


패키지 설명서를 읽어 보신 분은 아시겠지만 패키지 제작자는 미니멀(mininal) 테마를 사랑합니다. 우리도 똑같이 적용해 보겠습니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year))) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    facet_grid(year~.) +
    theme_minimal()


그런데 사실 질문자께서 원하셨던 건 이렇게 facet으로 나눈 게 아니었습니다. 한 낱말구름 안에서 위아래로 나뉜 형태를 원하셨던 것.


처음에는 y 값으로 해결할 수 있지 않을까 해서 이렇게 시도해 봤습니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year), y=year)) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    theme_minimal()



어느 정도 비슷하게 나왔습니다.


일단 y 축에 있는 선을 지우고 다시 보겠습니다.


scale_y_*에서 breaks 속성을 비워두면 y축 선이 사라집니다. R는 연도를 연속 값으로 받아들일 테니까 이번에는 scale_y_continuous()를 쓰면 됩니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year), y=year)) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    scale_y_continuous(breaks=NULL) +
    theme_minimal()


이런 스타일이 필요한 분도 계시겠지만 낱말구름을 그릴 때는 많이 나오는 낱말이 가운데에 나오면 좋습니다. 지금은 많이 나온 낱말이 2018년 자료는 y=2018에, 2019년도는 y=2019에 몰려 있습니다.


설명서를 조금더 열심히 읽어 보니 angle_group 속성을 활용하면 이 문제를 해결할 수 있다고 합니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year), angle_group=year)) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    theme_minimal()


예, 잘 나왔습니다. 일단 이걸로 일단 질문자께서 남기신 문제를 해결했습니다. 글자 크기 등은 다시 조정하면 될 겁니다.


그렇다면 만약 낱말구름을 좌우로 정렬하고 싶을 때는 어떻게 하면 될까요?


처음에는 그냥 다른 그래프처럼 coord_flip()을 바뀔 줄 알았습니다. 안 됩니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year), angle_group=year)) + 
    geom_text_wordcloud_area(eccentricity=2) +
    scale_size_area(max_size=14) +
    theme_minimal() +
    coord_flip()


그래서 생각한 게 글자 방향을 돌리는 겁니다. angle 속성을 조절하면 방향을 바꿀 수 있습니다. 왼쪽으로 90도씩 돌려서 일단 이런 결과를 얻었습니다.

ggplot(m, aes(label=corpus, size=n, color=factor(year), angle_group=factor(year), angle=90)) +
    geom_text_wordcloud_area() +
    scale_size_area(max_size=14) +
    theme_minimal()


일단 이 그래프를 그림으로 저장하고 나면 그림을 돌리는 일도 아닙니다. 포토샵 같은 그래픽 처리 프로그램을 통해 그냥 회전을 시켜주면 그만이기 때문. 아래는 이런 식으로 얻은 최종 결과물입니다.



그래도 이렇게 작업을 진행하는 건 꼼수라면 분명 꼼수입니다. 혹시 정상적인(?) 방법으로 이 문제를 해결하실 줄 아는 분이 계시다면 알려주시면 대단히 감사하겠습니다.


그러면 여러분 모두 Happy Charting!


댓글,

KindeR | 카테고리 다른 글 더 보기