DoITgrow

[시각화] 파이썬으로 한글 워드클라우드(Word Cloud) 생성하고 원하는 이미지 형태로 출력하기 본문

딥러닝 & 머신러닝/자연어 처리 (Natural Language Processing)

[시각화] 파이썬으로 한글 워드클라우드(Word Cloud) 생성하고 원하는 이미지 형태로 출력하기

김수성 (Kim SuSung) 2021. 11. 29. 23:24
반응형

안녕하세요. 오늘 소개해드릴 코드는 한글 문서의 단어를 추출하여 워드클라우드(Word Cloud)로 시각화하는 방법입니다.

파이썬에서 시각화는 거의 모두 matplotlib 라이브러리를 기반으로 하고 있습니다. 그러나 기본적으로 한글을 지원하지 않기 때문에 한글 데이터를 시각화할 경우 폰트가 깨지는 문제가 발생하여 이 부분에 대해서 다뤄보고자 합니다.

그리고 생성한 워드 클라우드의 그림을 우리가 원하는 이미지 형태로 나타낼 수 있는 방법 또한 소개드리려고 합니다.

포스팅 주요 내용

1. konlpy 패키지를 통한 한글 텍스트 추출 및 간단한 전처리

2. 한글로 워드클라우드 시각화

3. 원하는 이미지로 워드클라우드 생성하기

그럼 바로 본론으로 들어가겠습니다~

0. 필요 패키지 불러오기

from wordcloud import WordCloud
import matplotlib.pyplot as plt
from collections import Counter
from konlpy.tag import Okt
from PIL import Image
import numpy as np

▲ 오늘 학습할 기본 패키지의 구성입니다.

  • from wordcloud import WordCloud
    - 이 패키지는 말그대로 워드클라우드를 생성에 필요한 기본 모듈입니다.
  • import matplotlib.pyplot as plt
    - 생성한 워드클라우드 데이터를 시각화하여 그리기 위해 불러옵니다.
  • from collections import Counter
    - 텍스트를 추출하고, 빈도 수를 추출하기 위해 사용합니다. 기본적으로 워드클라우드는 단어의 출현 빈도가 클수록 더 크게 그려집니다.
  • from konlpy.tag import Okt
    - 한국어를 처리하는 대표적인 형태소 분석 패키지입니다. Okt, Kkma 등 여러가지 패키지들이 존재하는데 형태소 분석기마다 명사, 명사 등의 형태소를 조금씩 다르게 처리하므로 다양하게 사용해본 후, 가지고 있는 문서 특성에 적합한 형태소 분석기를 사용하는 것이 좋습니다.
  • from PIL import Image
    - 워드클라우드를 원하는 형태로 그리기 위해 그림을 불러오는 패키지입니다.
  • import numpy as np
    - 불러온 그림을 배열로 나타내어 쉽게 처리할 수 있도록 도와주는 패키지입니다.

1. konlpy 패키지를 통한 한글 텍스트 추출 및 간단한 전처리

오늘 사용할 한글 문서는 "대한민국헌법.txt" 파일입니다. 간단히 따라해보실 분들은 아래 텍스트 파일을 받으셔서 사용하셔도 되고, 본인이 가지고 있는 한글 문서가 있다면 그걸로 사용해 보셔도 될 것 같아요.

대한민국헌법.txt
0.04MB

with open('대한민국헌법.txt', 'r', encoding='utf-8') as f:
    text = f.read()

okt = Okt()
nouns = okt.nouns(text) # 명사만 추출

words = [n for n in nouns if len(n) > 1] # 단어의 길이가 1개인 것은 제외

c = Counter(words) # 위에서 얻은 words를 처리하여 단어별 빈도수 형태의 딕셔너리 데이터를 구함

▲ 먼저 txt 파일을 읽어서 모든 내용을 text 변수에 저장했습니다. 그리고 Okt 형태소 분석기 객체를 생성한 후, nouns 함수를 통해 명사만 추출하여 nouns 변수에 담았습니다.

그리고 nouns 변수에 들어있는 단어들 중에서 단어의 길이가 1개인 것들은 큰 의미가 없는 단어라 생각하여 제외하였습니다.

마지막으로 Counter 객체를 통해 단어별 빈도수 딕셔너리 데이터를 얻었고, 이를 c 변수에 담았습니다.

2. 한글로 워드클라우드 시각화

wc = WordCloud(font_path='malgun', width=400, height=400, scale=2.0, max_font_size=250)
gen = wc.generate_from_frequencies(c)
plt.figure()
plt.imshow(gen)

▲ 워드클라우드를 생성하기 위해서 제일 먼저 해야할 일은 큰 템플릿을 준비하는 것입니다. 템플릿 정보에는 대표적적으로 그림 크기(width, height, scale, max_font_size) 등의 정보를 넣어주는데 여기서 제일 중요한 것은 바로 한글 폰트를 지정하는 것입니다. 

윈도우 사용자를 기준으로 폰트 정보는 "C:\Windows\Fonts"에서 확인할 수 있습니다. 해당 폴더에 들어가면 아래와 같이 다양한 폰트 정보를 확인할 수 있습니다. 여기서 원하는 폰트 파일에 마우스 오른쪽 버튼을 클릭하고 "속성(R)"을 클릭하면 아래 두번째 스크린샷과 같이 폰트의 파일명을 확인할 수 있습니다.

워드클라우드에 사용할 폰트를 고르셨으면 WordCloud 객체를 생성할 때, font_path 파라미터에 폰트 파일명을 똑같이 넣어주면 됩니다. (단, 폰트가 한글을 지원해야만 합니다.)

▼ 작성한 코드를 실행하면 아래와 같이 시각화된 워드클라우드 결과를 확인할 수 있습니다.

여기서 파일로 추출하고 싶다면 아래의 코드를 추가하시면 됩니다.

wc.to_file('법전_워드클라우드.png')

3. 원하는 이미지로 워드클라우드 생성하기

2번까지만 하셔도 간단한 코드 몇 줄로 워드클라우드를 결과를 활용할 수 있지만 픽토그래픽과 같이 워드클라우드를 특정한 이미지 형태로 출력할 수 있다면 그 전달력은 매우 높아질 것 같아요. 그래서 원하는 이미지로 워드클라우드를 생성하는 방법을 추가로 소개드리려고 합니다.

일단 법전에 관한 워드클라우드이므로 책 모양의 워드클라우드로 나타낸다면 그 전달력이 더 커질 것이라 생각했어요.

그래서 책 사진을 웹 상에서 구할려고 했는데 혹시나 포스팅할 경우 저작권 등에 걸리지 않을까하여 제가 직접 사진을 찍어서 템플릿을 만드는 방향으로 작업을 진행했습니다. 템플릿을 만드는 것이 특별한 노하우는 아니지만 간단히 해볼 수 있는 방법을 같이 말씀드릴게요~. 

조금 더 두껍고 법전 같은 책이 있다면 좋을텐데 그런 두꺼운 책은 없고 옆에 있는 책을 이용하여 사진을 찍어서 사용했습니다. 이렇게 찍은 사진은 템플릿으로 사용하기 위해 아래와 같이 책의 누끼를 따고, 배경과 구분되도록 색깔의 명암비를 크게 차이나게 만들었습니다.

그래픽 작업은 누구나 쉽게 사용할 수 있는 파워포인트를 이용해 봤구요. 그림을 클릭하면 생성되는 위의 "그림 형식" 또는 "그림 서식" 메뉴에 가면 "배경 제거"라는 기능을 이용할 수 있습니다. 이것을 이용해서 책 이외의 배경은 제거하였는데, 인터넷에서 누끼를 잘 따주는 홈페이지도 많으니 편한 방법을 이용하시면 될 것 같아요. 그리고 "그림 서식"으로 들어가서 그림의 "밝기"를 -100%하여 책 모양 부분을 검은색으로 처리하였습니다.

참고로 워드클라우드를 넣을 공간을 검게 만드는 이유는 뒤의 코드를 보면 이해하시겠지만 우리가 사용하는 이미지를 Image 패키지를 통해 숫자로 변환하면 이미지 위치의 색깔에 따라 0~255 사이의 값을 출력하게 되는데 여기서 0으로 표시된 부분에 워드클라우드가 그려지게 됩니다. 

최종적으로 만든 템플릿 이미지는 아래와 같습니다. 생각보다 깔끔하게 책 모양으로 얻은 것 같네요.

책_검은배경.jpg

img = Image.open('책_검은배경.jpg')
img_array = np.array(img)

wc = WordCloud(font_path='malgun', width=400, height=400, scale=2.0, max_font_size=250, mask=img_array)
gen = wc.generate_from_frequencies(c)

plt.figure()
plt.imshow(gen)

▲ 그럼 마지막으로 템플릿을 이용하여 워드클라우드를 그려보았습니다. 먼저 Image.open 함수를 통해 이미지를 불러와서 데이터를 img 변수에 넣었습니다. 

이렇게 불러온 이미지는 대략 아래와 같은 데이터 형태를 가지고 있습니다. 아래 예시는 간단히 가로 5픽셀, 세로 5픽셀의 이미지로 255가 하얀색 영역, 0이 검은색 영역인 것을 보여드린 것입니다. 

[[255, 255, 255, 255, 255],

 [255,   0,   0,   0,   255],

 [255,   0,   0,   0,   255],

 [255,   0,   0,   0,   255],

 [255, 255, 255, 255, 255]]

실제 이미지의 가로, 세로 픽셀이 훨씬 더 크고, 색깔도 단순히 0~255를 가지지 않고, RGB값(0~255, 0~255, 0~255)으로 가질 수 있는데 일단 그냥 진행해도 워드클라우드는 그려지니까 크게 신경 안쓰셔도 될 것 같아요. 만약 오류가 발생한다면 img_array 변수에 들어있는 숫자 데이터를 보고 데이터를 처리해줘야 할 수 도 있습니다.

여기서 기존 코드와 다른 점은 이미지를 배경으로 사용하기 위해 WordCloud 객체를 생성할 때, "mask" 추가 파라미터를 지정했다는 것입니다.

 

▼ 이렇게해서 최종적으로 얻은 워드클라우드 시각화 결과는 아래와 같았습니다. 막상 워드클라우드로 그려보니 책 느낌이 조금 사라지긴 했네요. 책이 더 두껍고, 사진 각도를 더 아래에서 찍었다면 더 법전 같은 느낌이 들 것 같네요.

마치며

이렇게 해서 한글 폰트를 이용하여 워드클라우드로 만드는 방법과 원하는 이미지로 그리는 방법까지 소개해드렸습니다. 더 많은 아이디어를 적용해서 좋은 시각화 결과를 얻으시길 바라며, 궁금하신 점이나 오류가 발생하는 부분은 댓글로 문의주시면 빠르게 답변드리겠습니다.

반응형
13 Comments
  • 프로필사진 추레하니 2021.12.03 23:57 최고입니다. 그렇지 않아도 궁금했는데 재미있습니다.
    사실은 tweepy 에러 때문에 방문했다가 에러도 해결하고 마스크 기법도 배웠네요. 감사합니다.^^
  • 프로필사진 김수성 (Kim SuSung) 2021.12.09 22:17 신고 재밌으셨다니 뿌듯하네요^^.
    앞으로도 새롭고 재밌는 것들 많이 알아내서 공유 드릴게요!
  • 프로필사진 추레하니 2021.12.10 22:29 혹시 c의 dict구조에서 상위 20개만 추려서 만들려면 어떻게 해야 할까요?
    Counter 설명을 찾아봐도 해결하기 어렵네요
  • 프로필사진 김수성 (Kim SuSung) 2021.12.10 22:37 신고 c = Counter(words)에서 c 객체를 얻으셨다면, c.most_common(n=20) 함수를 통해 단어 빈도 수가 상위 20개인 것들만 뽑아내실 수 있어요.
    근데 c.most_common(n=20) 코드 자체는 [(단어1, 빈도수), (단어2, 빈도수)]와 같이 튜플 모음의 리스트로 리턴을 해주기 때문에 dict(c.most_common(n=20))로 해서 딕셔너리로 형태로 변환한 후 다음 단계를 진행하면 돼요.
    * 요약
    c = Counter(words)
    c = dict(c.most_common(n=20)) <- 코드 추가
  • 프로필사진 추레하니 2021.12.11 20:01 감사합니다. ^^,
    튜플로 리턴 된 것을 어떻게 처리하나 했는데 ~해결을 알려주셨네요.
  • 프로필사진 구교운 2022.07.06 17:15 The _imagingft C module is not installed
    해당 오류가 발생하는데, 혹시 알고 계신 부분이 있을까요??
    ------------------------
    wc = WordCloud(font_path = 'HANDotum', width = 500 , scale=2.0 , max_font_size = 250)
    gen = wc.generate_from_frequencies(c) # 위에서 만든 단어 빈출도를 저장하고 있는 자료

    plt.figure()
    plt.imshow(gen)
    ---------------여기까지가 코드고

    File ~\anaconda3\lib\site-packages\PIL\ImageFont.py:43, in _imagingft_not_installed.__getattr__(self, id)
    42 def __getattr__(self, id):
    ---> 43 raise ImportError("The _imagingft C module is not installed")

    ImportError: The _imagingft C module is not installed
    ----
    여기까지가 오류코드입니다.

    윈도우 10 64bit 주피터노트북상에서 실행시키고 있습니당..
  • 프로필사진 구교운 2022.07.06 17:49 해결하였습니다. 혹시 비슷한 에러 겪고 계신 분들은

    PIL 대신에
    https://www.lfd.uci.edu/~gohlke/pythonlibs/#pillow
    에서 현재 실행환경(파이썬 버젼) 에 맞는 whl 파일 설치한 뒤 `pip install <다운파일명.whl>` 으로 대체하시고 다시 시도해보세요~~
  • 프로필사진 구교운 2022.07.06 17:50 문제는 x64 환경에서 pip나 easy_install을 사용하여 라이브러리를 설치하는 경우에 x86으로 컴파일이 된다고 한다.친절히도 (검증되진 않았지만) 많이 사용되는 라이브러리의 바이너리 버전 설치파일 링크가 있다.
    출처: https://nnoco.tistory.com/116 [Sentio, ergo sum:티스토리]

    참고내용입니당
  • 프로필사진 김수성 (Kim SuSung) 2022.07.21 20:23 신고 제가 요세 다른 일이 있어서 확인이 늦어졌는데 해결하시고, 팁까지 공유해 주셔서 감사합니다^^. 저도 많은 도움 될 것 같아요!
  • 프로필사진 손난영 2022.08.27 02:46 안녕하세요 ^^ 포스팅을 보고 왕초보인 저도 할 수 있었어요. 학생들에게 줄 수업 자료를 만들고 있는데 간단하고 유용하게 사용할 수 있었어요. 감사합니다!! 제거하고 싶은 명사가 있는 경우 어떻게 해야하는지 궁금합니다.
  • 프로필사진 김수성 (Kim SuSung) 2022.09.25 14:50 신고 답변이 너무 늦었네요! 죄송해요.
    제가 다른 일 시작하는게 있어서 집중하다 보니 블로그 관리에 소홀했네요!

    제거하고 싶은 명사가 있는 경우 아래 부분을 추가해 보세요!

    with open('대한민국헌법.txt', 'r', encoding='utf-8') as f:
    text = f.read()

    okt = Okt()
    nouns = okt.nouns(text) # 명사만 추출

    # 변경한 부분
    filter_words = ['단어1', '단어2']
    words = [n for n in nouns if len(n) > 1 and n not in filter_words] # 단어의 길이가 1개이고 필터링할 것은 제외

    c = Counter(words) # 위에서 얻은 words를 처리하여 단어별 빈도수 형태의 딕셔너리 데이터를 구함
  • 프로필사진 김남우 2022.09.20 14:39 좋은자료 잘 보고 갑니다~ mac에서 실행하니 바로 되네요.
  • 프로필사진 김수성 (Kim SuSung) 2022.09.25 14:51 신고 덕담 감사합니다^^.
댓글쓰기 폼