이전 포스팅에서 Correlated Topic Model을 통해서 뉴스 기사를 분석하고 주제 간의 상관관계를 뽑아낸 적이 있습니다. 최근 tomotopy에 CTM을 추가해서 누구나 쉽게 따라해볼 수 있게 된 김에 간단하게 따라해볼 수 있는 코드를 공유드립니다!
기본 코드는 tomotopy github의 예제코드(https://github.com/bab2min/tomotopy/blob/master/examples/ctm_network.py)와 동일하되, 전처리 부분만 한국어 전용으로 변경되었습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
import tomotopy as tp # 토픽 모델링에 사용할 패키지 from kiwipiepy import Kiwi # 한국어 형태소 분석에 사용할 패키지 from pyvis.network import Network # 네트워크 시각화에 사용할 패키지 try : # 이미 전처리된 코퍼스가 있으면 불러온다. corpus = tp.utils.Corpus.load( 'k.cps' ) except IOError: # 없으면 전처리를 시작한다. kiwi = Kiwi() kiwi.prepare() # 형태소 분석 후 사용할 태그 pat_tag = re. compile ( 'NN[GP]|V[VA]|MAG|MM' ) def tokenizer(raw, user_data): res = next (user_data) for w, tag, start, l in res: if not pat_tag.match(tag) or len (w) < = 1 : continue yield w + ( '다' if tag.startswith( 'V' ) else ''), start, l corpus = tp.utils.Corpus( tokenizer = tokenizer ) # 입력 파일에는 한 줄에 문헌 하나씩이 들어가 있습니다. corpus.process((line, kiwi.tokenize([line])) for line in open ( '입력 텍스트 파일.txt' , encoding = 'utf-8' )) # 전처리한 코퍼스를 저장한다. corpus.save( 'k.cps' ) # 최소 10개 이상 문헌에 등장하고, 전체 출현빈도는 20 이상인 단어만 사용합니다. # 그리고 상위 10개 고빈도 단어는 분석에서 제외하구요 # 주제 개수는 40개입니다. mdl = tp.CTModel(tw = tp.TermWeight.ONE, min_df = 10 , min_cf = 20 , rm_top = 10 , k = 40 , corpus = corpus) mdl.train( 0 ) # 문헌 수가 만 개 이상이라면 num_beta_sample을 1~5 정도로 줄여도 됨 # 수 천개라면 최소 10 정도, 수 백개에 불과하다면 20 이상으로 키우는걸 권장 mdl.num_beta_sample = 1 print ( 'Num docs:{}, Num Vocabs:{}, Total Words:{}' . format ( len (mdl.docs), len (mdl.used_vocabs), mdl.num_words )) print ( 'Removed Top words: ' , * mdl.removed_top_words) # 총 1000회 깁스샘플링을 반복합니다. # 적절한 반복회수는 데이터에 따라 다릅니다. # ll_per_word 값의 증가가 둔화되거나 멈추는 지점까지만 # 반복하는걸 추천합니다. for i in range ( 0 , 1000 , 20 ): print ( 'Iteration: {:04}, LL per word: {:.4}' . format (i, mdl.ll_per_word)) mdl.train( 20 ) print ( 'Iteration: {:04}, LL per word: {:.4}' . format (i, mdl.ll_per_word)) # 학습된 결과를 시각화 합니다. g = Network(width = 800 , height = 800 , font_color = "#333" ) correl = mdl.get_correlations().reshape([ - 1 ]) correl.sort() # 상관계수 상위 10%만 간선으로 잇습니다. top_tenth = mdl.k * (mdl.k - 1 ) / / 10 top_tenth = correl[ - mdl.k - top_tenth] topic_counts = mdl.get_count_by_topics() for k in range (mdl.k): label = "#{}" . format (k) title = ' ' .join(word for word, _ in mdl.get_topic_words(k, top_n = 8 )) print ( 'Topic' , label, title) label + = '\n' + ' ' .join(word for word, _ in mdl.get_topic_words(k, top_n = 3 )) g.add_node(k, label = label, title = title, shape = 'ellipse' , value = float (topic_counts[k])) for l, correlation in zip ( range (k - 1 ), mdl.get_correlations(k)): if correlation < top_tenth: continue g.add_edge(k, l, value = float (correlation), title = '{:.02}' . format (correlation)) g.barnes_hut(gravity = - 1000 , spring_length = 20 ) g.show_buttons() # 시각화 파일이 topic_network.html 이라는 이름으로 저장됩니다. # 웹 브라우저로 열어서 확인해보세요. g.show( "topic_network.html" ) |
분석이 잘 되었다면 최종적으로 생성된 topic_network.html 파일을 열어 결과물을 확인해보시면 됩니다.
네트워크를 그린 결과는 위와 같습니다. 노드(동그라미)는 각각의 주제를 나타내며 안에 들어가 있는 단어 3개는 상위 단어입니다. 상관계수가 상위 10% 안에 드는 경우 노드 사이에 선을 그어주었습니다. 선의 굵기는 상관계수의 크기를 나타냅니다. 마우스를 올리면 상관계수 값을 볼 수도 있습니다. 주제 간의 상관관계를 분석해야하는 경우가 있다면 CTM을 사용해보시기를 권합니다!
Kiwi로 한국어 문장 분리하기 (10) | 2021.12.23 |
---|---|
Lamon : 라틴어 품사 태거 개발기 (4) | 2020.10.20 |
범용적인 감정 분석(극성 분석)은 가능할까 (11) | 2020.07.08 |
[Python] tomotopy로 문헌별 토픽 비중 계산하기 (6) | 2019.12.01 |
Chrono-gram을 이용해 라틴어 고문헌 연대 추정하기 (3) | 2019.09.16 |
[토픽 모델링] 대량의 문헌을 주제에 따라 클러스터링해보기 (3) | 2019.07.10 |
댓글 영역