언어에 따라 문법과 문장 구성이 다르듯, 자연어 처리도 영어와 한국어에서 다르게 진행된다. 지난 포스팅에서는 영어를 중심으로 한 토큰화를 알아 보았다. 이번 포스팅에서는 한국어 토큰화를 알아보자.
영어는 기본적으로 띄어쓰기를 단위로 하는 '어절'을 기준으로 토큰화를 하기 때문에 어절 토큰화와 단어 토큰화가 같다. 이때, New York과 같은 합성어나 he's와 같은 줄임말에 대한 예외 처리만 하면 된다. 그러나 한국어는 '나는(나+는)', '한다(하+-ㄴ다)'와 같이 조사, 어미 등을 붙여 말을 만들기 때문에 어절을 기준으로 토큰화 하는 것을 지양한다. 따라서 한국어는 보통 형태소를 기준으로 토큰화를 진행한다.
KoNLPy 패키지로는 다음의 과정을 수행할 수 있다.
- morphs : 형태소 추출
- pos : 품사 태깅
- nouns : 명사만 추출
이 패키지에는 Hannanum, Kkma, Komoran, Mecab, Okt(Twitter) 분석기가 있는데, 이중 우선 mecab은 제외하고 네 가지 분석기들의 형태소 추출(morphs) 방식만 비교해 보자. 문장은 대한민국헌법 제1장 제3조를 가지고 왔다.
pip install konlpy
from konlpy.tag import Kkma, Hannanum, Komoran, Okt
hannanum = Hannanum()
kkma = Kkma()
komoran = Komoran()
okt = Okt()
sentence = '제3조 대한민국의 영토는 한반도와 그 부속도서로 한다.'
# hannanum : KAIST SWRC(Semantic Web Research Center)에서 개발
print(f'Hannanum 형태소 분석기: {hannanum.morphs(sentence)}')
# KKma : 서울대학교 IDS(intelligent Data Systems) 연구실에서 개발
print(f'KKma 형태소 분석기: {kkma.morphs(sentence)}')
# Komoran
print(f'Komoran 형태소 분석기: {komoran.morphs(sentence)}')
# okt: 오픈 소스 한국어 분석기, 과거 트위터 형태소 분석기
print(f'okt 형태소 분석기: {okt.morphs(sentence)}')
----------
Hannanum 형태소 분석기: ['제3조', '대한민국', '의', '영토', '는', '한반도', '와', '그', '부속도서', '로', '하', 'ㄴ다', '.']
KKma 형태소 분석기: ['저', '의', '3', '조', '대한민국', '의', '영토', '는', '한반도', '와', '그', '부속', '도', '서로', '하', 'ㄴ다', '.']
Komoran 형태소 분석기: ['제', '3', '조', '대한민국', '의', '영토', '는', '한반도', '와', '그', '부속', '도서', '로', '하', 'ㄴ다', '.']
okt 형태소 분석기: ['제', '3조', '대한민국', '의', '영토', '는', '한반도', '와', '그', '부속', '도서', '로', '한다', '.']
분석기마다 토큰화 기준이 다른 것을 확인할 수 있다.
이제 분석기별로 형태소 분석(morphs), 품사 태깅(pos), 명사만 추출(nouns)하는 과정을 실습해 보자. 각각에서 강한 분석기가 다 다른 듯하다.
print('hannanum 형태소 분석 :',hannanum.morphs("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('hannanum 품사 태깅 :',hannanum.pos("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('hannanum 명사 추출 :',hannanum.nouns("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
----------
hannanum 형태소 분석 : ['철없', '어', '보이', '지', '말', 'ㄴ', '성숙', '하고', ',', '생각', '없', '어', '보이', '지', '말', 'ㄴ', '따뜻한', '짱구', '가', '좋', '아', '!']
hannanum 품사 태깅 : [('철없', 'P'), ('어', 'E'), ('보이', 'P'), ('지', 'E'), ('말', 'P'), ('ㄴ', 'E'), ('성숙', 'N'), ('하고', 'J'), (',', 'S'), ('생각', 'N'), ('없', 'P'), ('어', 'E'), ('보이', 'P'), ('지', 'E'), ('말', 'P'), ('ㄴ', 'E'), ('따뜻한', 'N'), ('짱구', 'N'), ('가', 'J'), ('좋', 'P'), ('아', 'E'), ('!', 'S')]
hannanum 명사 추출 : ['성숙', '생각', '따뜻한', '짱구']
print('kkma 형태소 분석 :',kkma.morphs("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('kkma 품사 태깅 :',kkma.pos("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('kkma 명사 추출 :',kkma.nouns("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
----------
kkma 형태소 분석 : ['철없', '어', '보이', '지만', '성숙', '하', '고', ',', '생각', '없', '어', '보이', '지만', '따뜻', '하', 'ㄴ', '짱구', '가', '좋', '아', '!']
kkma 품사 태깅 : [('철없', 'VA'), ('어', 'ECD'), ('보이', 'VV'), ('지만', 'ECE'), ('성숙', 'NNG'), ('하', 'XSV'), ('고', 'ECE'), (',', 'SP'), ('생각', 'NNG'), ('없', 'VA'), ('어', 'ECD'), ('보이', 'VV'), ('지만', 'ECE'), ('따뜻', 'XR'), ('하', 'XSA'), ('ㄴ', 'ETD'), ('짱구', 'NNG'), ('가', 'JKS'), ('좋', 'VA'), ('아', 'ECD'), ('!', 'SF')]
kkma 명사 추출 : ['성숙', '생각', '짱구']
print('komoran 형태소 분석 :',komoran.morphs("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('komoran 품사 태깅 :',komoran.pos("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('komoran 명사 추출 :',komoran.nouns("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
----------
komoran 형태소 분석 : ['철없', '어', '보이', '지만', '성숙', '하', '고', ',', '생각', '없', '어', '보이', '지만', '따뜻', '하', 'ㄴ', '짱', '구가', '좋', '아', '!']
komoran 품사 태깅 : [('철없', 'VA'), ('어', 'EC'), ('보이', 'VV'), ('지만', 'EC'), ('성숙', 'NNG'), ('하', 'XSV'), ('고', 'EC'), (',', 'SP'), ('생각', 'NNG'), ('없', 'VA'), ('어', 'EC'), ('보이', 'VV'), ('지만', 'EC'), ('따뜻', 'XR'), ('하', 'XSA'), ('ㄴ', 'ETM'), ('짱', 'MAG'), ('구가', 'NNG'), ('좋', 'VA'), ('아', 'EF'), ('!', 'SF')]
komoran 명사 추출 : ['성숙', '생각', '구가']
print('OKT 형태소 분석 :',okt.morphs("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('OKT 품사 태깅 :',okt.pos("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
print('OKT 명사 추출 :',okt.nouns("철없어 보이지만 성숙하고, 생각 없어 보이지만 따뜻한 짱구가 좋아!"))
----------
OKT 형태소 분석 : ['철', '없어', '보이', '지만', '성숙하고', ',', '생각', '없어', '보이', '지만', '따뜻한', '짱구', '가', '좋아', '!']
OKT 품사 태깅 : [('철', 'Noun'), ('없어', 'Adjective'), ('보이', 'Noun'), ('지만', 'Josa'), ('성숙하고', 'Adjective'), (',', 'Punctuation'), ('생각', 'Noun'), ('없어', 'Adjective'), ('보이', 'Noun'), ('지만', 'Josa'), ('따뜻한', 'Adjective'), ('짱구', 'Noun'), ('가', 'Josa'), ('좋아', 'Adjective'), ('!', 'Punctuation')]
OKT 명사 추출 : ['철', '보이', '생각', '보이', '짱구']
이렇듯 각 형태소 분석기는 성능과 결과가 다르기 때문에 용도에 따라 적합한 분석기를 선택하여 사용하면 된다. 예를 들어, 품사 태깅을 자세히 보고 싶다면 kkma를 사용하면 될 것이다(형태소 분석기별 tagset : hannanum-29, kkma-67, komoran-45, okt-19개). 또한, 속도를 중시한다면 위에서 실습하지는 않았지만 konlpy 패키지에 포함되어 있는 메캅을 사용할 수도 있다.
이번 포스팅에서는 한국어의 특징에 따라 영어와는 다른 토큰화 방식이 필요함을 인식하고, konlpy 패키지를 활용하여 분석기별로 형태소 분석, 품사 태깅, 명사 추출을 해보았다. 다음 포스팅에서는 이번 포스팅에 이어 자연어처리에서의 간단한 전처리 과정을 전체적으로 살펴볼 예정이다.
덕분에 마무리 복습하고 기분좋게 잡니다ㅋㅋㅋ🙃