한글 데이터 머신러닝 및 word2vec을 이용한 유사도 분석

A. 설치
1.  한글 처리 분야의 prototyping에 python이 가장 적합합니다.

2. python용 버전관리 소프트웨어 pip를 설치합니다.
sudo easy_install pip

3. gensim을 설치합니다. (Gensim은 Python 기반의 Text mining library이며, 토픽 모델링, word2vec도 지원합니다.)
sudo pip install -U gensim

4. NLTK를 설치합니다. (자연어 처리를 위해 광범위하게 쓰이는 Python library입니다.)
sudo pip install nltk

5. KoNLPy를 설치합니다. (한글처리를 위한 library입니다.)
sudo pip install konlpy

6. twython를 설치합니다. (twitter api를 쉽게 사용하기위해 필요합니다.)
sudo pip install twython

B. NLTK와 konlpy, twython으로 텍스트 다루기
1. 읽기
$ python
from konlpy.corpus import kobill    # Docs from pokr.kr/bill
files_ko = kobill.fileids()         # Get file ids
doc_ko = kobill.open(‘news.txt’).read()
# news.txt는 http://boilerpipe-web.appspot.com/ 를 통해 포탈뉴스 데이터를 수집
# news.txt 는  konlpy의 corpus 아래에 있는 kobill directory에 미리 저장되어있어야 함
# /Library/Python/2.7/site-packages/konlpy/data/corpus/kobill

2.Tokenize (의미단어를 검출합니다.)
from konlpy.tag import Twitter; t = Twitter()
tokens_ko = t.morphs(doc_ko)

3. Token Wapper 클래스를  만듭니다.(token에 대한 처리를 위해 필요합니다.)
import nltk
ko = nltk.Text(tokens_ko, name=’뉴스’)   # 이름

4. 토근 정보 및 단일 토큰 정보를 확인합니다.
print(len(ko.tokens))       # returns number of tokens (document length)
print(len(set(ko.tokens)))  # returns number of unique tokens
ko.vocab()                  # returns frequency distribution

5. 챠트로 확인합니다.
ko.plot(50) #상위 50개의 unique token에 대해서 plot한 결과를 아래와 같이 보여줍니다.

 

 

왼쪽부터 잦은 빈도로 출현한 단어들입니다. …과 같은 의미없는 특수문자들을 제외하면 요즘 유행하는 메르스가 역시 가장 높은 빈도수(약 30건) 정도를 보여주고 있습니다. 적절한 토큰나이저로 특수문자들을 걸러준다면 의미있는 결과를 얻어내기 용이합니다.

6. 특정 단어에 대해서 빈도수를 확인합니다.
print(ko.count(str(‘메르스’)))

결과)
18
위처럼 하면 메르스에 대한 숫자를 줍니다. 만약에 제대로 글자를 인식 못한다면, 파일의 앞에 아래처럼 디폴트 인코딩을 세팅해 줍니다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)

7. 분산 차트 보기 (dispersion plot)
ko.dispersion_plot([‘메르스’,’학교’,’병원’])

 

 

8. 색인하기 (본문속에서 해당 검색어가 포함된 문장을 찾아주는 작업입니다.)
ko.concordance(unicode(‘메르스’))

결과) 문장들이 출력됩니다.

9.유의어 찾기
ko.similar(unicode(‘메르스’))

결과)

의미 있는 유의어 출력을 확인할 수 있습니다.

10. 의미단위로 나누기 (Tagging and chunking)
10.1 형태소 분석기(POS tagging)
from konlpy.tag import Twitter; t = Twitter()
tags_ko = t.pos(unicode(‘작고 노란 강아지가 고양이에게 짖었다’))
print(tags_ko)

결과)
[(u’\uc791\uace0′, u’Noun’), (u’\ub178\ub780′, u’Adjective’), (u’\uac15\uc544\uc9c0′, u’Noun’), (u’\uac00′, u’Josa’), (u’\uace0\uc591\uc774′, u’Noun’), (u’\uc5d0\uac8c’, u’Josa’), (u’\uc9d6\uc5c8′, u’Noun’), (u’\ub2e4′, u’Josa’)]

명사,형용사, 조사등을 나누어 보여줍니다.

10.2 명사구 단위로 그룹화하기 (Noun Phrase Chunking)
parser_ko = nltk.RegexpParser(“NP: {<Adjective>*<Noun>*}”)
chunks_ko = parser_ko.parse(tags_ko)
chunks_ko.draw()

결과)

 

 

위처럼 NP(Noun Phrase)단위로  문장구조를 보여줍니다.

C. Topic Modeling 과 Word Embedding(Word2Vec)
1. 요점
Python gensim library로 아래 두가지 작업을 많이 합니다. 간단한 실행과정 입니다.

– Topic Modeling
: 어떤 문서에서 자주 나타는 단어를 통해, 주제를 찾아주는 확률적인 모델을 디자인합니다.
유명한 것으로 LDA, LSI, HDP가 있습니다.

– Word Embedding
문장속의 단어간의 관계를 비지도 학습 방식으로 분석하여 만들어지는 수십~ 수백차원의 벡터로서 특징(Feature)화 되는 단어들을 만들어 냅니다. 단어가 가지고있는 벡터간의 연산을 통해 다른 단어와의 관계를 만들어내게 됩니다.

2. 한글처리
word2vec에서 한글처리를 해주려면 아래 몇가지 요소를 고려해야 합니다.

2.1. UTF8 디폴트 처리
아래처럼 파일의 최상단에 선언합니다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)

2.2. konlpy 라이브러리 설정
– 한글 파일들의 위치는 konlpy의 corpus 아래에 있는 kobill directory에 읽을 파일들이 미리 저장되어 있어야 합니다.
/Library/Python/2.7/site-packages/konlpy/data/corpus/kobill

– 토크나이저를 설정합니다. nltk방식처럼 nltk + twitter api를 사용해서 토근화합니다.
#load from kobill
from konlpy.corpus import kobill
docs_ko = [kobill.open(i).read() for i in kobill.fileids()]
#Tokenize
from konlpy.tag import Twitter; t = Twitter()
pos = lambda d: [‘/’.join(p) for p in t.pos(d)]
texts_ko = [pos(doc) for doc in docs_ko]

3. 사용례
3.1. Topic Modeling (LSI, LDA, HDP 알고리즘)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)
from konlpy.corpus import kobill
docs_ko = [kobill.open(i).read() for i in kobill.fileids()]
from konlpy.tag import Twitter; t=Twitter()
pos = lambda d: [‘/’.join(p) for p in t.pos(d, stem=True, norm=True)]
texts_ko = [pos(doc) for doc in docs_ko]

#encode tokens to integers
from gensim import corpora
dictionary_ko = corpora.Dictionary(texts_ko)
dictionary_ko.save(‘ko.dict’)  # save dictionary to file for future use

#calulate TF-IDF
from gensim import models
tf_ko = [dictionary_ko.doc2bow(text) for text in texts_ko]
tfidf_model_ko = models.TfidfModel(tf_ko)
tfidf_ko = tfidf_model_ko[tf_ko]
corpora.MmCorpus.serialize(‘ko.mm’, tfidf_ko) # save corpus to file for future use
#train topic model

#LSI
ntopics, nwords = 3, 5
lsi_ko = models.lsimodel.LsiModel(tfidf_ko, id2word=dictionary_ko, num_topics=ntopics)
print(lsi_ko.print_topics(num_topics=ntopics, num_words=nwords))

#LDA
import numpy as np; np.random.seed(42)  # optional
lda_ko = models.ldamodel.LdaModel(tfidf_ko, id2word=dictionary_ko, num_topics=ntopics)
print(lda_ko.print_topics(num_topics=ntopics, num_words=nwords))

#HDP
import numpy as np; np.random.seed(42)  # optional
hdp_ko = models.hdpmodel.HdpModel(tfidf_ko, id2word=dictionary_ko)
print(hdp_ko.print_topics(topics=ntopics, topn=nwords))

#Scoring document
bow = tfidf_model_ko[dictionary_ko.doc2bow(texts_ko[0])]
sorted(lsi_ko[bow], key=lambda x: x[1], reverse=True)
sorted(lda_ko[bow], key=lambda x: x[1], reverse=True)
sorted(hdp_ko[bow], key=lambda x: x[1], reverse=True)
bow = tfidf_model_ko[dictionary_ko.doc2bow(texts_ko[1])]
sorted(lsi_ko[bow], key=lambda x: x[1], reverse=True)
sorted(lda_ko[bow], key=lambda x: x[1], reverse=True)
sorted(hdp_ko[bow], key=lambda x: x[1], reverse=True)

result) 아래 결과를 통해 육야휴직, 임신에 대한 글들이 대부분이라는 것을 알수 있습니다.

==LSI==
[u’0.527*”육아휴직/Noun” + 0.261*”만/Noun” + 0.231*”%xd7/Foreign” + 0.217*”대체/Noun” + 0.204*”고용/Noun”‘, u’0.455*”파견/Noun” + 0.417*”부대/Noun” + 0.266*”UAE/Alpha” + 0.246*”○/Foreign” + 0.195*”국군/Noun”‘, u’-0.313*”결혼/Noun” + -0.276*”손해/Noun” + -0.255*”예고/Noun” + -0.210*”ㆍ/Foreign” + -0.204*”입법/Noun”’]

===LDA===
[u’0.002*육아휴직/Noun + 0.001*만/Noun + 0.001*…/Foreign + 0.001*%xd7/Foreign + 0.001*고용/Noun’, u’0.001*결혼/Noun + 0.001*손해/Noun + 0.001*학위/Noun + 0.001*간호/Noun + 0.001*원사/Noun’, u’0.002*육아휴직/Noun + 0.001*만/Noun + 0.001*부대/Noun + 0.001*대체/Noun + 0.001*파견/Noun’]

==HDP==
[u’topic 0: 0.004*임신/Noun + 0.003*놓다/Verb + 0.003*육아휴직/Noun + 0.003*부/Noun + 0.003*하루/Noun’, u’topic 1: 0.004*공/Noun + 0.003*시험/Noun + 0.003*생략/Noun + 0.003*러버/Noun + 0.003*학년/Noun’, u’topic 2: 0.004*질타/Noun + 0.003*724/Number + 0.003*열/Noun + 0.003*15/Number + 0.003*WHO/Alpha’]

3.2. Word2Vec을 이용한 Word Embedding
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)

#load
from konlpy.corpus import kobill
docs_ko = [kobill.open(i).read() for i in kobill.fileids()]

#Tokenize
from konlpy.tag import Twitter; t = Twitter()
pos = lambda d: [‘/’.join(p) for p in t.pos(d)]
texts_ko = [pos(doc) for doc in docs_ko]

#train
from gensim.models import word2vec
wv_model_ko = word2vec.Word2Vec(texts_ko)
wv_model_ko.init_sims(replace=True)
wv_model_ko.save(‘ko_word2vec_e.model’)

#test
print(wv_model_ko.most_similar(pos(‘메르스’)))

Result)
메르스라는 단어에 대해 유사검색을 실행했고, 첫번째 유사도로 찾은 단어는 \ubcd1\uc6d0 로서, “병원”입니다.
(출력된 결과를 유니코드 변환 사이트에서 돌려보면 금방 확인이 가능합니다.(http://allog.tistory.com/41)  )

[(u’병원/Noun’, 0.9664202928543091), (u”‘/Punctuation”, 0.9501774311065674), (u’…/Foreign’, 0.945787250995636), (u'”/Punctuation’, 0.8908506631851196), (u’%xb7/Foreign’, 0.8733454942703247), (u'[/Punctuation’, 0.8687864542007446), (u’]/Punctuation’, 0.8462499976158142), (u’연합뉴스/Noun’, 0.8382998704910278), (u’공개/Noun’, 0.8208351731300354), (u’있어/Adjective’, 0.8137425184249878)] [(u’취학/Noun’, 0.9841623306274414), (u’중인/Noun’, 0.9737297296524048), (u’號/Foreign’, 0.9697698950767517), (u’학년/Noun’, 0.9695179462432861), (u’第/Foreign’, 0.9606421589851379), (u’조정함/Verb’, 0.9572989344596863), (u’상향/Noun’, 0.9528375864028931), (u’지방/Noun’, 0.949833869934082), (u’여자/Noun’, 0.9465466737747192), (u’44/Number’, 0.9451450109481812)]

한글 데이터 분석에서 gensim 조합은 매우 좋은 선택입니다. 사용법이 매우 쉬우며 이미 잘 정리된 library들이 있습니다.

NLTK + KoNLPy + Word2Vec이면 많은 문제를 직관적으로 해결할수 있습니다.

원문 : http://blog.naver.com/PostView.nhn?blogId=2feelus&logNo=220384206922&redirect=Dlog&widgetTypeCall=true

Tags:

word2vec

nlp

KoNLPy