한국어 문장을 분석하려면 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈작업을 제일 먼저 수행해야 한다.
이때 토큰 단위를 어떻게 정의하느냐에 따라 자연어 처리 성능에 영향을 준다.
일단 형태소(𝒎𝒐𝒓𝒑𝒉𝒆𝒎𝒆)를 토큰 단위로 사용하고자 한다.
형태소는 일정한 의미가 있는 가장 작은 말의 단위이다. 즉, 의미가 더 이상 쪼개지지 않는 단어를 의미한다.
형태소를 토큰 단위로 사용할 경우 단어와 품사 정보를 같이 활용할 수 있기 때문에 효과적이다.
영어의 경우 단어의 변화가 크지 않고, 띄어쓰기로 단어를 구분하기 때문에 공백을 기준으로 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈을 수행해도 큰 문제 없다.
하지만 한국어는 명사와 조사를 띄어 쓰지 않고, 용언에 따라 여러 가지 어미가 붙기 때문에 띄어쓰기만으로는 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈 할 수 없다.
따라서 한국어의 복잡한 특성에 따라 문장에서 형태소를 분석할 수 있는 도구가 필요한데, 이를 형태소 분석기라 한다.
형태소 분석기는 문장에서 형태소뿐만 아니라 어근, 접두사/접미사, 품사 등 다양한 언어적 속성의 구조를 파악주며, 특히 문장에서 형태소를 추출하면서 형태소의 뜻과 문맥을 고려해 품사 태깅을 해준다.
Konlpy에서 제공하는 세 가지 종류의 형태소 분석기를 살펴 보고자 한다.
Kkma 꼬꼬마
Kkma는 서울대학교 IDS(𝐼𝑛𝑡𝑒𝑙𝑙𝑖𝑔𝑒𝑛𝑡 𝐷𝑎𝑡𝑎 𝑆𝑦𝑠𝑡𝑒𝑚𝑠)연구실에서 자연어 처리를 위해 개발한 한국형 형태소 분석기다.
Kkma는 ‘꼬꼬마’로 발음하며, GPL v2라이선스를 사용한다.
✔ Kkma에서 제공하는 함수
◼ morphs(phrase)
- 인자로 입력한 문장을 형태소 단위로 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈 한다.
- 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈된 형태소들은 리스트 형태로 반환된다.
◼ nouns(phrase)
- 인자로 입력한 문장에서 품사가 명사인 토큰만 추출한다.
◼ pos(phrase, flatten=True)
- POS tagger라 부르며, 인자로 입력한 문장에서 형태소를 추출한 뒤 품사 태깅을 한다.
- 추출된 형태소와 그 형태소의 품사가 튜플 형태로 묶여서 리스트로 반환된다.
◼ setences(phrase)
- 인자로 입력한 여러 문장을 분리해주는 역할을 한다.
- 분리된 문장은 리스트 형태로 반환된다.
✔ 실습
from konlpy.tag import Kkma
kkma = Kkma()
text = '안녕하세요 꼬꼬마 입니다.'
#형태소 추출
morphs = kkma.morphs(text)
print(morphs)
# ['안녕', '하', '세요', '꼬꼬마', '이', 'ㅂ니다', '.']
#형태소와 품사 태그 추출
pos = kkma.pos(text)
print(pos)
# [('안녕', 'NNG'), ('하', 'XSV'), ('세요', 'EFN'), ('꼬꼬마', 'NNG'), ('이', 'VCP'), ('ㅂ니다', 'EFN'), ('.', 'SF')]
#명사만 추출
nouns = kkma.nouns(text)
print(nouns)
# ['안녕', '꼬꼬마']
#문장 분리
sentences = "안녕하세요 반갑습니다. 저는 꼬꼬마 입니다."
s = kkma.sentences(sentences) # 문장 단위로 토크나이징
print(s)
# ['안녕 하세요 반갑습니다.', '저는 꼬꼬마 입니다.']
Kkma의 경우 다른 형태소 분석기에 비해 분석 시간이 느리지만 Okt(𝑂𝑝𝑒𝑛 𝐾𝑜𝑟𝑒𝑎𝑛 𝑡𝑒𝑥𝑡) 기준의 품사 태그에 비해 지원하는 품사 태그가 다양하다.
따라서 속도가 느리더라도 정확한 품사 정보가 필요할 때는 Kkma를 많이 사용한다.
※ Kkma 한글 형태소 품사(Part Of Speech, POS) 태그표 : http://kkma.snu.ac.kr/documents/?doc=postag
Komoran(𝐾𝑜𝑟𝑒𝑎𝑛 𝑀𝑜𝑟𝑝ℎ𝑜𝑙𝑜𝑔𝑖𝑐𝑎𝑙 𝐴𝑁𝑎𝑙𝑦𝑧𝑒𝑟) 코모란
Komoran은 Shineware에서 자바로 개발한 한국어 형태소 분석기이다.
‘코모란’으로 발음하며, Apache 라이선스 2.0을 따르는 오픈소스 소프트웨어이다.
경량화 버전도 존재하며, 다른 형태소 분석기와 다르게 공백이 포함된 형태소 단위로도 분석이 가능해 많이 사용한다.
✔ Komoran에서 제공하는 함수
◼ morphs(phrase)
- 인자로 입력한 문장을 형태소 단위로 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈 한다.
- 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈된 형태소들은 리스트 형태로 반환된다.
◼ nouns(phrase)
- 인자로 입력한 문장에서 품사가 명사인 토큰만 추출한다.
◼ pos(phrase, flatten=True)
- POS tagger라 부르며, 인자로 입력한 문장에서 형태소를 추출한 뒤 품사 태깅을 한다.
- 추출된 형태소와 그 형태소의 품사가 튜플 형태로 묶여서 리스트로 반환된다.
✔ 실습
from konlpy.tag import Komoran
komoran = Komoran()
text = "안녕 나는 komoran이야"
# 형태소 추출
morphs = komoran.morphs(text)
print(morphs)
# ['안녕', '나', '는', 'komoran', '이야']
#형태소와 품사 태그 추출
pos = komoran.pos(text)
print(pos)
# [('안녕', 'NNP'), ('나', 'NP'), ('는', 'JX'), ('komoran', 'SL'), ('이야', 'JX')]
#명사만 추출
nouns = komoran.nouns(text)
print(nouns)
# ['안녕']
Komoran은 Kkan보다 형태소를 빠르게 분석하며 다양한 품사 태그를 지원합니다.
Okt(𝑂𝑝𝑒𝑛𝑠𝑜𝑢𝑟𝑐𝑒 𝐾𝑜𝑟𝑒𝑎𝑛 𝑇𝑒𝑥𝑡 𝑃𝑟𝑜𝑐𝑒𝑠𝑠𝑜𝑟)
Okt는 트위터에서 개발한 Twitter 한국어 처리기에서 파생된 오픈소스 한국어 처리기이다.
공식 홈페이지에 따르면 Okt는 빅데이터에서 간단한 한국어 처리를 통해 색인어를 추출하는 목표를 갖고 있기 때문에 완전한 수준의 형태소 분석을 지향하지 않는다. 따라서 공식적으로는 Okt를 한국어 처리기라 표현하고 있다.
Okt는 띄어쓰기가 어느 정도 되어 있는 문장을 빠르게 분석할 때 많이 사용된다.
✔ Okt 에서 제공하는 함수
◼ morphs(phrase)
- 인자로 입력한 문장을 형태소 단위로 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈 한다.
- 𝒕𝒐𝒌𝒆𝒏𝒊𝒛𝒊𝒏𝒈된 형태소들은 리스트 형태로 반환된다.
◼ nouns(phrase)
- 인자로 입력한 문장에서 품사가 명사인 토큰만 추출한다.
◼ pos(phrase, stem=False, join=False)
- POS tagger라 부르며, 인자로 입력한 문장에서 형태소를 추출한 뒤 품사 태깅을 한다.
- 추출된 형태소와 그 형태소의 품사가 튜플 형태로 묶여서 리스트로 반환된다.
◼ normalize(phrase)
- 입력한 문장을 정규화시킨다.
(정규화 이전 : 사랑핵ㅋㅋ → 정규화 이후 : 사랑해 ㅋㅋ)
◼ phrases(phrase)
- 입력한 문장에서 어구를 추출한다. (입력 : 오늘 날씨가 좋아요. → 출력 : [‘오늘’, ‘오늘 날씨’, ‘날씨’])
✔ 실습
from konlpy.tag import Okt
okt = Okt() #Okt 형태소 분석기 객체 생성
text = "안녕 나는 Okt 라고 해"
morphs = okt.morphs(text) #형태소 추출
print(morphs)
# ['안녕', '나', '는', 'Okt', '라고', '해']
pos = okt.pos(text) #형태소와 품사 태그 추출
print(pos)
# [('안녕', 'Noun'), ('나', 'Noun'), ('는', 'Josa'), ('Okt', 'Alpha'), ('라고', 'Josa'), ('해', 'Noun')]
nouns = okt.nouns(text) #명사만 추출
print(nouns)
# ['안녕', '나', '해']
text = "안녕하세요 반갑습니닼ㅋㅋㅋㅋ 게임 한 판 하실래욬ㅋㅋ"
print(okt.normalize(text)) #정규화, 어구 추출
# 안녕하세요 반갑습니다ㅋㅋㅋ 게임 한 판 하실래요ㅋㅋ
print(okt.phrases(text))
# ['게임', '게임 한 판']
Okt의 경우 앞서 소개한 형태소 분석기들보다 분석되는 품사 정보는 작지만 분석 속도는 제일 빠르다.
또한 normalize() 함수를 지원해 오타가 섞인 문장을 정규화해서 처리하는데 효과적이다.
형태소 분석기에서 인식하지 못하는 단어들을 직접 추가하는 방법
형태소 분석을 하다보면 형태소 분석이 되지 않는 단어들이 있다.
이런 경우 사용자 단어 사전(user word dictionary)를 만들어 단어가 인식이 될 수 있도록 만들어 준다.
Komoran
from konlpy.tag import Komoran
komoran = Komoran()
text = "코모란은 형태소 분석기의 종류 중 하나이다."
pos = komoran.pos(text)
print(pos)
# [('코', 'NNG'), ('모란', 'NNP'), ('은', 'JX'), ('형태소', 'NNP'), ('분석기', 'NNG'), ('의', 'JKG'),
# ('종류', 'NNG'), ('중', 'NNB'), ('하나', 'NR'), ('이', 'VCP'), ('다', 'EF'), ('.', 'SF')]
'코모란' 이라는 단어를 사용자 단어 사전에 넣어서 한 단어로 인식되게 만들었다.
komoran = Komoran(userdic='data/user_dic.tsv')
text = "코모란은 형태소 분석기의 종류 중 하나이다."
pos = komoran.pos(text)
print(pos)
# [('코모란', 'NNP'), ('은', 'JX'), ('형태소', 'NNP'), ('분석기', 'NNG'), ('의', 'JKG'),
# ('종류', 'NNG'), ('중', 'NNB'), ('하나', 'NR'), ('이', 'VCP'), ('다', 'EF'), ('.', 'SF')]
Kkma
Kkma 형태소 분석기는 userdic 을 사용 할 수 없다.
# 사전에 정의하는 방법
1. konlpy내의 java폴더로 이동
2. kkma-2.0.jar 압축풀기
3. kkma-2.0 > dic 폴더로 이동 및 파일 확인
- kkma에서 형태소 분석에 사용하는 사전들을 확인 할 수 있다.
4. 파일 내용 확인 및 사전 변경
- 원하는 단어를 추가해준다.
5. jar 파일 만들기
- 수정한 내용을 적용하기 위해서는 jar 파일로 만들고 기존의 kkma-2.0.jar과 바꿔줘야 한다.
# jar 파일로 만드는 방법
1) 명령 프롬프트 실행
2) konlpy내의 java/kkma-2.0 폴더로 이동
(예 : cd C:\Users\user\Anaconda3\Lib\site-packages\konlpy\java\kkma-2.0\)
3) 명령어 : jar -cvf 생성하고자하는파일명.jar/ .
예 : jar -cvf user.jar/ .
6. 새로운 kkma-2.0.jar을 적용하기
user.jar 파일을 kkma-2.0.jar로 이름을 변경해주면 된다.
문제가 생길 수 있으니 기존의 kkma-2.0.jar 파일은 백업해두고 변경해주세요.
7. 결과 확인하기
Customized KoNLPy
영어는 띄어쓰기만해도 단어가 잘 분리되나 한국어는 경우가 다르다.
형태소 분석기를 사용할 때 이러한 상황을 극복하기 위해 하나의 해결책으로써 형태소 분석기에 사용자 사전을 추가해 주는 경우가 있다.
from ckonlpy.tag import Twitter
twitter = Twitter()
twitter.morphs('아이오아이는 아이돌 입니다.')
# ['아이오', '아이', '는', '아이돌', '입니다', '.']
twitter.add_dictionary('아이오아이', 'Noun')
twitter.morphs('아이오아이는 아이돌 입니다.')
# ['아이오아이', '는', '아이돌', '입니다', '.']
더 자세한 내용을 알고싶다면 여기를 참고하세요
SOYNLP
soynlp는 품사 태깅, 단어 토큰화 등을 지원하는 단어 토크나이저이다.
비지도 학습으로 단어 토큰화를 한다는 특징을 갖고 있으며, 데이터에 자주 등장하는 단어들을 단어로 분석한다.
soynlp 단어 토크나이저는 내부적으로 단어 점수 표로 동작하며, 이 점수는 응집 확률(cohesion probability)과 브랜칭 엔트로피(branching entropy)를 활용한다.
기존의 형태소 분석기는 신조어나 형태소 분석기에 등록되지 않은 단어 같은 경우에는 제대로 구분하지 못하는 단점이 있었다.
soynlp는 이러한 단점을 해결하기 위해 이러한 단어의 앞, 뒤에 독립된 다른 단어들이 계속해서 등장하는 것을 파악하고, 반복하여 등장한다면 한 단어로 파악하는 과정을 거쳐 작업을 진행한다.
✔ 학습하기
import urllib.request
from soynlp import DoublespaceLineCorpus
from soynlp.word import WordExtractor
urllib.request.urlretrieve("https://raw.githubusercontent.com/lovit/soynlp/master/tutorials/2016-10-20.txt", filename="2016-10-20.txt")
훈련데이터를 다수의 문서로 분리 후 학습이 진행이 된다.
(전체 코퍼스로부터 응집 확률과 브랜칭 엔트로피 단어 점수표를 만들게 된다.)
# 문서 나누기
corpus = DoublespaceLineCorpus("2016-10-20.txt")
len(corpus) #30091
word_extractor = WordExtractor()
word_extractor.train(corpus)
word_score_table = word_extractor.extract() # 전체 코퍼스에 대한 단어 점수표 계산
training was done. used memory 5.186 Gb
all cohesion probabilities was computed. # words = 223348
all branching entropies was computed # words = 361598
all accessor variety was computed # words = 361598
✔ SOYNLP 응집 확률
- 응집 확률은 내부 문자열(substring)이 얼마나 응집하여 자주 등장하는지를 판단하는 척도이다.
- 내부 문자열을 만드는 과정에서 왼쪽부터 순서대로 문자열을 추가하면서 각 문자열이 주어졌을 시 다음 문자가 나올 확률을 계산한다.
- 이 값을 높을수록 전체 코퍼스에서 문자열 시퀀스는 하나의 단어로 등장할 확률이 높다는 뜻이다.
"안녕하세요" 라는 단어의 스코어를 구하는 과정
$cohension(2) = P(안녕|안)$
$cohension(3) = \sqrt[2]{P(안녕|안)\cdot P(안녕하|안녕)}$
$cohension(4) = \sqrt[3]{P(안녕|안)\cdot P(안녕하|안녕)\cdot P(안녕하세|안녕하)}$
$cohension(5) = \sqrt[4]{P(안녕|안)\cdot P(안녕하|안녕)\cdot P(안녕하세|안녕하)\cdot P(안녕하세요|안녕하세)}$
word_score_table["안녕하"].cohesion_forward # 0.09661931790419788
word_score_table["안녕하세"].cohesion_forward # 0.17685936076040082
word_score_table["안녕하세요"].cohesion_forward # 0.27272254325817824
✔ SOYNLP의 브랜칭 엔트로피(branching entropy)
Branching Entropy는 확률 분포의 엔트로피값을 사용함으로써 주어진 문자열에서 얼마나 다음 문자가 등장할 수 있는지 판단할 수 있는 척도의 값이다. (다음에 나올 문자의 선택지가 많을수록 값이 커지게 된다)
word_score_table["디스"].right_branching_entropy # 1.6371694761537934
# 값이 0이 된 이유는 다음에 올 문자가 명확하기 때문이다.
word_score_table["디스플"].right_branching_entropy # -0.0
# 값이 다시 올라간 이유는 문자 시퀀스 다음에는 조사나 다른 단어와 같은 다양한 경우가 있을 수 있기 떄문이다.
word_score_table["디스플레이"].right_branching_entropy # 3.1400392861792916
✔ SOYNLP의 L tokenizer
한국어에서 띄어쓰기 단위로 나눈 어절 토큰은 L토큰 + R토큰의 형식을 가지는 경우가 많은데 분리 기준을 점수가 가장 높은 L토큰을 찾는 원리를 가지고 있다.
from soynlp.tokenizer import LTokenizer
scores = {word:score.cohesion_forward for word, score in word_score_table.items()}
l_tokenizer = LTokenizer(scores=scores)
l_tokenizer.tokenize("우리의 미래는 밝다", flatten=False)
# [('우리', '의'), ('미래', '는'), ('밝다', '')]
✔ 최대 점수 tokenizer
띄어쓰기가 되지 않는 문장에서 점수가 높은 글자 시퀀스를 순차적으로 찾아내는 토크나이저이다.
from soynlp.tokenizer import MaxScoreTokenizer
maxscore_tokenizer = MaxScoreTokenizer(scores=scores)
maxscore_tokenizer.tokenize("우리의미래는밝다")
# ['우리', '의', '미래', '는밝다']
✔ SOYNLP를 이용한 반복되는 문자 정제
SNS나 채팅의 경우 'ㅋㅋㅋ', 'ㅎㅎ' 같은 이모티콘의 경우 불필요하게 연속되는 경우가 많은데 반복되는 것을 하나로 정규화시켜줄 수 있다.
from soynlp.normalizer import *
print(emoticon_normalize('앜ㅋㅋㅋㅋㅠㅠㅠㅠㅠ', num_repeats=2)) # 아ㅋㅋㅠㅠ
print(emoticon_normalize('앜ㅋㅋㅋㅋㅋㅋㅋㅎㅎㅎㅠㅠㅠㅠ', num_repeats=2)) # 아ㅋㅋㅎㅎㅎㅠㅠ
print(emoticon_normalize('앜ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ큐ㅠㅠㅠㅠㅠ', num_repeats=2)) # 아ㅋㅋㅠㅠ
print(repeat_normalize('와아아아아아아', num_repeats=2)) # 와아아
print(repeat_normalize('우아아아아아아아아아아아아', num_repeats=2)) # 우아아
print(repeat_normalize('오아이이이이이우우', num_repeats=2)) # 오아이이우우
'NLP' 카테고리의 다른 글
어간 추출(Stemming)과 표제어 추출(Lemmatization) (0) | 2022.01.27 |
---|---|
토큰화 Tokenization (0) | 2022.01.27 |
불용어(Stop word) 제거 (0) | 2022.01.27 |
자연어 처리(Natural Language Processing)란 무엇인가? (0) | 2022.01.27 |
파이썬(Python) 한글 형태소 분석 Konlpy 설치하기 (0) | 2022.01.27 |