Data Analysis

텍스트 마이닝, 형태소 분석, Word Cloud, Kkma, Jpype1, Konlpy, 대통령 연설문 분석하기

김심슨 2025. 5. 31. 14:52

1. 텍스트 마이닝이란?

말이나 글 속에 숨겨진 "유의미한 정보"를 뽑아내는 작업 

예 :

뉴스 기사 10만개를 수집해서 자주 등장하는 키워드 찾기 

고객 리뷰 1만개를 분석해서 불만족하는 패턴 찾기

트위터 글을 분석해서 감정(긍정/부정)을 예측하는 것

 

2. 텍스트 마이닝에서 하는 일 

- 수집 : 뉴스, 리뷰, 블로그, 트윗 등 텍스트를 모음 

- 정제 : 특수문제 제거, 띄어쓰기 교정 등 깨끗하게 만듦

- 분석 : 빈도수, 감성, 클러스터링, 키워드 추출 등 

- 시각화 : 워드 클라우드, 막대그리프 등으로 보여줌 

 

3. 형태소 분석 (Morphological Analysis)

문장을 의미 있는 단어 단위로 쪼개고, 각각의 품사를 분석하는 과정 (텍스트 마이닝을 하기 전처리 단계)

(특히 한국어철머 어미 변화가 많은 언어는 반드시 필요)

예 : " 나는 학교에 간다 " -> 형태소 분석 결과 

단어(형태소) 품사

명사
조사
학교 명사
조사
동사 어간
ㄴ다 어미

 

4. 형태소 분석 라이브러리 

  • KoNLPy (한국어 전용 패키지)
    • Okt, Komoran, Hannanum, Kkma 등 다양한 형태소 분석기
  • mecab (가장 빠르고 정확, 실무에서 많이 씀)

< 대통령 연설문 텍스트 분석 및 시각화 >

 

1. 텍스트 로딩 

moon = open('assets/speech_moon.txt', encoding='utf-8').read()
print(moon)

 

2. 한글이 아닌 모든 문자 제거 

import re #정규표현식
moon = re.sub('[^가-힣]',' ', moon)  # 한글을 제외한 모든 문자는 공백으로 바꿈

인자 : 패턴문자열, 대체문자열, 전체문자열 

 

import re : 정규 표현식 (Regular Expression) 모듈 : 문자열에서 특정한 규칙(패턴)을 찾아서 처리할 수 있게 해주는 도구

 

< 정규표현식 주요 함수 >

- re.sub() : 패턴에 맞는 걸 바꾼다 (replace)

- re.findall() : 패턴에 맞는 걸 찾아서 리스트로 반환 

- re.search() : 첫 번째로 패턴에 맞는 걸 찾아서 반환 

- re.match() : 문자열의 시작이 패턴과 맞는지 확인  

 

3. 명사 추출 

import konlpy #한글 형태소 분석 라이브러리, 자바 설치 필수 (jdk11)
hannanum = konlpy.tag.Hannanum()
nouns = hannanum.nouns(moon) // 명사로만 추출함

------
['정권교체', '정치교체', '시대교체', '불비불명', '고사', '남쪽', '언덕', '나뭇가지', '년', '동안', '새', '한번', '하늘', '끝', '한번',

Hannanum() : 한국어 텍스트 분석을 위한 형태소 분석기 중 하나 

- 문장을 형태소 단위로 나눔 (명사, 조사, 동사 등)

- 품사 태그 달기 

- 구(Phrase) 추출 등도 가능 

 

아래처럼 쓰기도 함 

from konlpy.tag import Hannanum
hannanum = Hannanum()

 

예시 : konlpy의 Hannanum()

from konlpy.tag import Hannanum
hannanum = Hannanum()

text = "나는 오늘 학교에 갔습니다."
print(hannanum.morphs(text))  # 형태소 추출
print(hannanum.pos(text))     # 형태소 + 품사 태깅

-------

['나', '는', '오늘', '학교', '에', '가', '았', '습니다', '.']
[('나', 'NP'), ('는', 'JX'), ('오늘', 'NNG'), ('학교', 'NNG'), ('에', 'JKB'), ...]

 

< konlpy에서 선택 가능한 분석기 종류 >

Okt() : 트위터에서 개발 -> 가장 대중적, 정확도 좋음 (실무에서 많이 사용)

Mecab() : 매우 빠르고 정확함 (실무 최강, 하지만 윈도우에 설치 어려움)

Hannanum() : 카이스트 개발 (실험/연구용)

Kkma() : 서울대 개발 (분석 범위는 넓으나, 단점은 느림)

Komoran() : Shineware 개발 (품사 세분화 잘 됨) 

 

4. 추출 명사를 데이터 프레임으로 

import pandas as pd
df_word = pd.DataFrame({'word': nouns}) #3번에서 만들어놓은 것
print(df_word)
df_word.info()

 

5. 각 명사의 글자수 추가 

df_word['count'] = df_word['word'].str.len() #각 명사들의 길이를 가지고 count라는 변수를 만들겠다

 

6. 글자수가 2 이상인 것 추출 

df_word = df_word.query('count>=2')
df_word = df_word.sort_values('count', ascending=False)
print(df_word)

query : 행 조건 필터링 함수 = df[df['cout'] >=2와 같은 의미

글자 수 기준으로 내림차순 정렬 (sort_value) : 데이터를 보기 좋게 정리할 때사용 

1글자 단어는 "것", "수" 등 의미 없는 단어가 많기 때문 

 

7. 단어 빈도 집계 

df_word = df_word.groupby('word', as_index=False) \
                .agg(n=('word', 'count')) \    // count 함수를 써서 등장횟수를 세고, 컬럼 명을 n으로
                .sort_values('n', ascending=False) // 등장 횟수 기준으로 내림차순 정렬

- groupby로 단어별 개수를 세고, 가장 많이 등장한 단어부터 정렬(내림차순)

 

+) 데이터 그룹별 개수 세기 기본 패턴 : 

df.groupby('컬럼명', as_index=False).agg(n=('컬럼명', 'count'))

 

8. 상위 20개 단어 시각화 

top20 = df_word.head(20)

- 가장 많이 등장한 단어 상위 20개만 따로 저장하기 

 

9. 막대 그래프 그리기 

# 막대그래프 그리기
import matplotlib.pyplot as plt
import seaborn as sns
# 그래프 설정
plt.rcParams.update({
    'font.family': 'Malgun Gothic', # 글자체
    'figure.dpi': '120', # 해상도
    'figure.figsize': [6.5, 6] # 그래프 크기
})
sns.barplot(data=top20, x='n', y='word')  # x축 =등장횟수, y축 : 단어 
plt.show()

 

10. 워드 클라우드 만들기 

font = 'assets/DoHyeon-Regular.ttf'

워드 클라우드는 한글 폰트 파일이 꼭 필요하다 -> 폰트 파일 경로를 지정해서 한글이 깨지지 않도록 

dic_word = df_word.set_index('word').to_dict()['n']

데이터프레임 형태였던 데이터를 워드클라우드가 받아들이기 쉽게 딕셔너리 형태로 바꿔준다. 

워드 클라우드는 {단어:빈도} 형태를 원함.

import matplotlib.pyplot as plt
from wordcloud import WordCloud

wc = WordCloud(
    random_state=1234,  //워드클라우드의 모양을 랜덤하게 하는 난수
    font_path=font, # 위에서 설정한 한글 폰트 경로
    width=400,
    height=400,
    background_color='white' # 배경색 설정
)

- random_state의 의미: 

img_wordcloud = wc.generate_from_frequencies(dic_word)

위에서 만든 딕셔너리 데이터를 기반으로 워드클라우드 이미지 생성 (단어의 빈도가 클수록 글자가 커짐)

 

plt.figure(figsize=(10, 10))
plt.axis('off') 
plt.imshow(img_wordcloud)
plt.show()

matplotlib로 이미지를 보여준다. 테두리 없애서 깔끔하게 보이도록 

11. 구름 모양으로 워드클라우드 만들기 (귀여움) - 워드 클라우드를 원하는 그림 모양으로 만들기 

 

from PIL import Image # 이미지 관련 라이브러리
icon = Image.open('assets/cloud.png') # 이미지 메모리에 로딩

PIL을 이용해 구름 모양의 이미지 파일을 메모리에 불러옴 

# 마스크(mask) 생성 : 이미지 중에 덮을 부분
import numpy as np
# RGB모드로 icon이미지의 크기와 동일한 크기의 흰색 배경 이미지를 생성
img = Image.new('RGB', icon.size, (255, 255, 255))
# 흰색 배경위에 icon이미지를 덮어씀
img.paste(icon, icon)
# 이미지를 넘파이 배열로 변환
img = np.array(img)

- 이미지 파일을  numpy 배열로 바꿔서 마스크 형태로 사용 

마스크(mask) 이미지 중 글씨가 들어갈 모양을 결정하는 역할 

wc = WordCloud(
    random_state=1234,
    font_path=font,
    width=400,
    height=400,
    background_color='white',
    mask=img,     # 이번엔 마스크를 넣어서 구름 모양으로 클라우드를 만듦 
    colormap='inferno' # 테마 색상
)
img_wordcloud = wc.generate_from_frequencies(dic_word)


 

< 최종 코드 >
# textmining1.py
# 대통령 연설문 텍스트 분석 및 시각화

# 텍스트 로딩
moon = open('assets/speech_moon.txt', encoding='utf-8').read()
#print(moon)

# 한글이 아닌 모든 문자 제거
import re
# 인자 : 패턴문자열, 대체문자열, 전체문자열
moon = re.sub('[^가-힣]',' ', moon)
#print(moon)

# 명사 추출
# konlpy : 한글 형태소 분석 라이브러리, java설치 필요(jdk11)
# 1. https://jdk.java.net/java-se-ri/11
# 2. Windows/x64 Java Development Kit (sha256) 파일 다운로드
# 3. 다운로드 받은 파일 압축 해제 후 java-11 디렉토리명을 java11로 변경
# 4. java11디렉토리를 D:\ai2504\에 복사
# 5. 내컴퓨터 우클릭 > 속성 > 고급시스템설정 > 고급 탭 > 환경변수 > 시스템환경변수
# 6. 새로만들기 > 변수명:JAVA_HOME, 변수값: D:\ai2504\java11
# 7. path변수 편집 > D:\ai2504\java11\bin 추가
# 설치테스트 : CMD > java -version
import konlpy
hannanum = konlpy.tag.Hannanum()
nouns = hannanum.nouns(moon)
# print(nouns)

# 추출한 명사를 데이터프레임으로
import pandas as pd
df_word = pd.DataFrame({'word': nouns})
#print(df_word)
#df_word.info()

# 각 명사의 글자수 추가
df_word['count'] = df_word['word'].str.len()
#print(df_word)

# 글자수가 2 이상인 것 추출
df_word = df_word.query('count>=2')
df_word = df_word.sort_values('count', ascending=False)
#print(df_word)

# 단어별 빈도 구하기
df_word = df_word.groupby('word', as_index=False) \
                .agg(n=('word', 'count')) \
                .sort_values('n', ascending=False)
#print(df_word)

# 단어별 빈도 막대그래프용 데이터 20개 추출
top20 = df_word.head(20)

# 막대그래프 그리기
# import matplotlib.pyplot as plt
# import seaborn as sns
# # 그래프 설정
# plt.rcParams.update({
#     'font.family': 'Malgun Gothic', # 글자체
#     'figure.dpi': '120', # 해상도
#     'figure.figsize': [6.5, 6] # 그래프 크기
# })
# sns.barplot(data=top20, x='n', y='word')
# plt.show()

 

< 정리 >

워드클라우드 기본 생성 방법 

wc = WordCloud(font_path=폰트 경로). generate_from_frequencies(딕셔너리)

 

마스크 이미지 적용 방법 

icon = Image.open('이미지경로.png')
img = np.array(icon)
wc = WordCloug(mask=img, font_path = 폰트 경로)