KoNLPy의 트위터 한국어 분석기 (현 오픈 한국어 분석기)는 속도도 빠르고 다양한 사전도 확보하고 있는 한국어 분석기입니다. 하지만 컴파일이 되어 있는 형태로 KoNLPy에 들어가 있기 때문에 사용자 사전의 추가가 힘들고*, 내가 원하는 임의의 태그를 지정할 수 없습니다.
customized_KoNLPy는 확실히 알고 있는 단어들에 대해서는 라이브러리를 거치지 않고 주어진 어절을 아는 단어들로 토크나이징 / 품사판별을 하는 기능을 제공합니다. 이를 위해 template 기반 토크나이징을 수행합니다.
사전: {'아이오아이': 'Noun', '는': 'Josa'}
탬플릿: Noun + Josa
위와 같은 단어 리스트와 탬플릿이 있다면 '아이오아이는' 이라는 어절은 [('아이오아이', 'Noun'), ('는', 'Josa')]로 분리됩니다.
* Scala 코드를 이용할 경우에는 사용자 사전의 추가가 매우 쉽습니다 참고
KoNLPy의 버전은 0.4.4 기준입니다. KoNLPy의 Twitter를 이용하여 '우리아이오아이는 정말 이뻐요'라는 문장을 처리하면 '아이오' + '아이'로 명사가 잘못 인식됩니다. 트와이스의 'tt' 역시 명사보다는 영어로 인식됩니다. 한국어 분석기 이지만, tt는 명사로 미리 분류하고 싶습니다.
In [18]:
import konlpy
konlpy.__version__
Out[18]:
In [1]:
from konlpy.tag import Twitter as OriginalTwitter
twitter_original = OriginalTwitter()
print(twitter_original.pos('우리아이오아이는 정말 이뻐요'),'\n')
print(twitter_original.pos('트둥이꺼 tt도 좋아요'))
customized_KoNLPy 에는 현재 트위터 한국어 분석기 만을 이용하는 wrapping class만 제공되고 있습니다. customized_KoNLPy의 Twitter는 본래 KoNLPy의 tag에 추가되는 함수가 있습니다.
Twitter.add_dictionary(words, tag)는 사용자가 사전을 추가할 수 있는 부분입니다. 단어를 하나씩 추가할 수 있습니다. 추가한 뒤 Twitter의 숨김 변수인 _dictionary._pos2words를 확인해보면 입력한 단어들을 볼 수 있습니다.
git clone을 한 상태에서 tutorial code를 이용하신다면 아래의 코드를 실행하여 path를 추가하십시요
In [2]:
import sys
sys.path.append('../')
In [3]:
from ckonlpy.tag import Twitter
twitter = Twitter()
twitter.add_dictionary('이', 'Modifier')
twitter.add_dictionary('우리', 'Modifier')
twitter.add_dictionary('이번', 'Modifier')
twitter.add_dictionary('아이오아이', 'Noun')
twitter.add_dictionary('행사', 'Noun')
twitter.add_dictionary('아이', 'Noun')
twitter.add_dictionary('번것', 'Noun')
twitter.add_dictionary('것', 'Noun')
twitter.add_dictionary('은', 'Josa')
twitter.add_dictionary('는', 'Josa')
twitter._dictionary._pos2words
Out[3]:
사전을 추가한 뒤, '아이오아이'가 명사로 제대로 인식됨을 확인할 수 있습니다.
In [4]:
twitter.pos('우리아이오아이는 정말 이뻐요')
Out[4]:
In [5]:
twitter.pos('아이오아이 이뻐요')
Out[5]:
사전을 추가할 때, 하나의 품사에 대하여 동시에 여러 개의 단어셋을 입력할 수도 있습니다.
Twitter.add_dictionary(words, tag)는 한번에 list of str 형식의 여러 개의 단어들을 입력할 수도 있습니다.
In [6]:
twitter.add_dictionary(['트와이스', 'tt', '트둥이', '꺼', '우리'], 'Noun')
twitter._dictionary._pos2words
Out[6]:
In [7]:
twitter.pos('트와이스tt는 좋아요')
Out[7]:
트위터 분석기의 조사사전을 이용할 수도 있습니다. Twitter()를 만들 때 argument를 넣을 수 있습니다.
In [8]:
twitter1 = Twitter(load_default_dictionary=True)
len(twitter1._dictionary._pos2words['Josa'])
Out[8]:
하지만 아직 '우리트둥이꺼tt는' 이라는 어절이 제대로 인식되지 않습니다. 그 이유는 templates에 'Noun + Noun + Josa'가 없었기 때문입니다. 이 경우에는 KoNLPy에 해당 어절을 분석하라고 보냅니다. 하지만 '트둥이'라는 단어를 알지 못해서 제대로 인식되지 않습니다.
In [9]:
twitter.pos('우리트둥이꺼tt는 좋아요')
Out[9]:
현재는 customized_tagger로 탬플릿 기반 토크나이저를 이용하고 있습니다. 어떤 탬플릿이 들어있는지 확인하기 위해서는 아래 부분을 확인하면 됩니다.
twitter._customized_tagger.templates
현재는 다음의 탬플릿이 입력되어 있습니다.
In [10]:
twitter._customized_tagger.templates
Out[10]:
기본 탬플릿은 customized_konlpy/data/templates/twitter_templates0 에 저장되어 있습니다. text 형식의 파일이며, 띄어쓰기로 아래와 같은 기본 템플릿을 지정하면 됩니다.
In [11]:
cat ../ckonlpy/data/templates/twitter_templates0
작업 중 탬플릿을 추가하고 싶다면, 탬플릿은 하나 단위로 tuple of str의 형식으로 입력할 수 있습니다. _customized_tagger.add_a_templated()은 중복되는 탬플릿이 아닌지 확인한 다음 탬플릿을 추가하는 함수입니다.
In [12]:
twitter._customized_tagger.add_a_template(('Modifier', 'Noun', 'Noun', 'Noun', 'Josa'))
twitter._customized_tagger.templates
Out[12]:
('Noun', 'Noun', 'Josa')가 입력되었고, '트와이스', 'tt'가 명사인지 알고 있기 때문에 아래 문장은 제대로 인식이 됩니다.
In [13]:
twitter.pos('우리트둥이꺼tt는 좋아요')
Out[13]:
사전을 추가할 때, 트위터 한국어 분석기에 존재하지 않는 태그가 들어가는 것을 방지하기 위해 tag의 값을 확인하는 부분이 구현되어 있습니다.
twitter.tagset
>>> {'Adjective': '형용사',
'Adverb': '부사',
'Alpha': '알파벳',
'Conjunction': '접속사',
'Determiner': '관형사',
'Eomi': '어미',
'Exclamation': '감탄사',
'Foreign': '외국어, 한자 및 기타기호',
'Hashtag': '트위터 해쉬태그',
'Josa': '조사',
'KoreanParticle': '(ex: ㅋㅋ)',
'Modifier': '관형사',
'Noun': '명사',
'Number': '숫자',
'PreEomi': '선어말어미',
'Punctuation': '구두점',
'ScreenName': '트위터 아이디',
'Suffix': '접미사',
'Unknown': '미등록어',
'Verb': '동사'}
twitter.tagset에 등록되어 있지 않는 품사에 대해서는 ValueError를 raise 합니다.
In [14]:
twitter.add_dictionary('lovit', 'Name')
하지만 Twitter.add_dictionary(words, tag, force=True)로 단어를 사전에 입력하면 알려지지 않은 품사라 하더라도 입력할 수 있습니다.
In [15]:
twitter.add_dictionary('lovit', 'Name', force=True)
twitter._dictionary._pos2words
Out[15]:
'Name'이라는 클래스 (더이상 품사가 아니므로)를 이용하는 탬플릿을 하나 입력한 뒤 pos에 입력하면 어절 'lovit은' customized_tagger에 의하여 처리가 되고, 사용자 사전에 알려지지 않은 어절인 '졸려'는 본래의 트위터 분석기에 의하여 처리가 됩니다.
In [16]:
twitter._customized_tagger.add_a_template(('Name', 'Josa'))
print(twitter._customized_tagger.templates)
twitter.pos('lovit은 이름입니다.')
Out[16]:
Templates를 이용하여도 후보가 여러 개 나올 수 있습니다. 여러 개 후보 중에서 best 를 선택하는 함수를 직접 디자인 할 수 도 있습니다. 이처럼 몇 개의 점수 기준을 만들고, 각 기준의 weight를 부여하는 방식은 트위터 분석기에서 이용하는 방식인데, 직관적이고 튜닝 가능해서 매우 좋은 방식이라 생각합니다.
In [17]:
score_weights = {
'num_nouns': -0.1,
'num_words': -0.2,
'no_noun': -1
}
def my_score(candidate):
num_nouns = len([w for w,t in candidate if t == 'Noun'])
num_words = len(candidate)
no_noun = 1 if num_nouns == 0 else 0
score = (num_nouns * score_weights['num_nouns']
+ num_words * score_weights['num_words']
+ no_noun * score_weights['no_noun'])
return score
twitter.set_selector(score_weights, my_score)
In [ ]: