노가다없는텍스트분석을위한한국어 NLP 파이콘코리아 2017 김현중 (soy.lovit@gmail.com) 1
노가다없는텍스트분석을위한한국어 NLP Hyunjoong Kim soy.lovit@gmail.com 2
KoNLPy 는 Python 에서사용할수있는한국어자연어처리패키지 from konlpy.tag import Kkma kkma = Kkma() print(kkma.nouns(u' 질문이나건의사항은깃헙이슈트래커에남겨주세요.')) [ 질문, 건의, 건의사항, 사항, 깃헙, 이슈, 트래커 ] print(kkma.pos(u' 오류보고는실행환경, 에러메세지와함께설명을최대한상세히!^^')) [( 오류, NNG), ( 보고, NNG), ( 는, JX), ( 실행, NNG), ( 환경, NNG), (,, SP), ( 에러, NNG), ( 메세지, NNG), ( 와, JKM), ( 함께, MAG), ( 설명, NNG), ( 을, JKO), ( 최대한, NNG), ( 상세히, MAG), (!, SF), (^^, EMO)] * http://konlpy.org/ko/latest/ 3
미등록단어문제 새롭게만들어진단어들은인식이잘되지않습니다 from konlpy.tag import Kkma, Twitter kkma = Kkma() twitter = Twitter() kkma.pos( 파이콘에서엔엘피이야기를합니다 ) 파이 /NNG, 콘 /NNG, 에서 /JKM, 엔엘피 /NNG, 이야기 /NNG, 를 /JKO, 하 /VV, ㅂ시다 /EF twitter.pos( 파이콘에서엔엘피이야기를합니다 ) 파 /Noun, 이콘 /Noun, 에서 /Josa, 엔 /Josa, 엘피 /Noun, 이야기 /Noun, 를 /Josa, 합 /Verb, 시 /PreEomi, 다 /Eomi 4
미등록단어문제 새롭게만들어진단어들은인식이잘되지않습니다 from konlpy.tag import Kkma, Twitter kkma = Kkma() twitter = Twitter() kkma.pos( 너무너무너무는아이오아이의노래에요 ) 너무 /MAG, 너무너무 /MAG, 는 /JX, 아이오 /NNG, 아이 /NNG, 의 /JKG, 노래 /NNG, 에 /JKM, 요 /JX twitter.pos( 너무너무너무는아이오아이의노래에요 ) 너무 /Noun, 너무 /Noun, 너무 /Noun, 는 /Josa, 아이오 /Noun, 아이 /Noun, 의 /Josa, 노래 /Noun, 에요 /Josa 5
미등록단어문제 이를해결하기위하여사용자사전을추가하여사용합니다 주로이작업은품사판별을한뒤, 빈도수가높은단어들중에서잘못처리된단어를고르는방식입니다 이반복적 / 노동집약적인과정을최대한자동화하는게목표입니다 6
우리가다룰이야기 사용자사전을사람이만들지말고, 데이터기반으로추출할것입니다 여러단어추출기법들중 cohesion 에대하여살펴봅니다. 단어중에서도명사는따로추출할것입니다 명사는새로운단어가가장많이생성되고사용도가장많이되는품사입니다 7
Part 1: 단어추출 + 토크나이징 Part 2: 명사추출 부록 : KoNLPy + 사용자사전 8
단어추출 + 토크나이징 https://github.com/lovit/soynlp 9
단어추출 우리도뉴스나글을읽으면서새로운단어들을쉽게학습합니다 단어는 ( 특히명사는 ) 경계에특징이있습니다. 우리는이를이용하여통계기반으로단어를추출합니다 단, 1 음절단어는제외합니다. 단어길이가 1 이면봐도무슨말인지해석하기힘듧니다 (= 모호합니다 ) 10
Cohesion (Character n-gram) 한국어의의미를지니는단어 ( 명사 / 동사 / 형용사 / 부사 ) 는어절왼쪽에있습니다 짜장면 / 명사 + 을 / 조사 먹 / 동사 + 었어 / 어미 11
Cohesion (Character n-gram) 맥락이충분히주어지지않으면다음에등장할글자의확률이작습니다 한글자 ( 아 ) 는매우모호한문맥입니다 > 아니 17.15 % 아이 한글자는특별한문맥을가지기가어렵습니다 > 아이 14.86 % > 아시 8.06 % > 아닌 4.74 % > 아파 4.43 % > 아직 3.85 % 12
Cohesion (Character n-gram) 맥락이충분히주어지지않으면다음에등장할글자의확률이작습니다 > 아이폰 16.60 % 아이오 어떤경우는두글자라하더라도다양한맥락에서등장하기도합니다 > 아이들 13.37 % > 아이디 9.66 % > 아이돌 6.77 % > 아이뉴 6.77 % > 아이오 6.53 % 13
Cohesion (Character n-gram) Subword 다음에등장할글자가쉽게예상된다면 ( 확률이높다면 ) 아직단어가 끝나지않았다는의미입니다 > 아이오아 87.95 % 아이오아 문맥이명확해질수록이전단어 다음글자확률이높아집니다 > 아이오닉 7.49 % > 아이오와 3.26 % > 아이오빈 0.65 % > 아이오페 0.33 % > 아이오케 0.33 % 14
Cohesion (Character n-gram) Subword 다음에등장할글자가쉽게예상된다면 ( 확률이높다면 ) 아직단어가 끝나지않았다는의미입니다 아이오아이 > 아이오아이 100.00 % 문맥이확실하면다음글자의등장확률이높습니다 15
Cohesion (Character n-gram) 단어의경계를넘으면다음글자에대한확률이다시작아집니다 > 아이오아이의 31.97 % 아이오아이는 단어경계뒤에는다양한조사 / 어미들이등장합니다 > 아이오아이는 27.21 % > 아이오아이와 13.61 % > 아이오아이가 12.24 % > 아이오아이에 9.52 % > 아이오아이까 1.36 % 16
Cohesion (Character n-gram) 단어의점수 (cohesion) 를아래처럼정의해봅니다 cohesion(c 1:n ) = n 1 n 1 i=1 P(c 1:i+1 c 1:i, ) P c 1:2 c 1 = #c 1:2 #c 1 cohesion( 아이오아이 ) = { p( 아 아이 ) * p( 아이 아이오 ) * p( 아이오 아이오아 ) * p( 아이오아 아이오아이 ) 학습은오로직 string count } 1/(5-1) 17
Cohesion (Character n-gram) 어절의왼쪽부터 subword 의빈도수를세어봅니다. docs = [ 파이콘에서발표를합니다, ] from collections import defaultdict count= defaultdict(lambda: 0) for doc in docs: for word in doc.split(): n = len(word) for e in range(1, n+1): count[word[:e]] += 1 18
Cohesion (Character n-gram) Subword 의빈도수와 P(AB A) 를계산해봅니다 word = ' 아이오아이는 n = len(word) for e in range(2, n+1): w = word[:e] f = count[w] p = f/count[:e-1] 아이, 아이오, 아이오아, 아이오아이, 아이오아이는, f=4910, p=0.15 f=307, p=0.06 f=270, p=0.88 f=270, p=1.00 f=40, p=0.15 print('{:6}, f={}, p={:.2}'. format(w, f, p)) 19
Cohesion (Character n-gram) 단어의점수 (cohesion) 를아래처럼구현해봅니다 def cohesion(w): return pow(count[w]/count[w[0]], 1/(len(w)-1)) 아이, 아이오, f=4910, s=0.15 f=307, s=0.10 word = ' 아이오아이가 n = len(word) for e in range(2, n+1): w = word[:e] f = count[w] s = cohesion(w) print('{:6}, f={}, s={:.2}'. format(w, f, s)) 아이오아, 아이오아이, f=270, s=0.20 f=270, s=0.30 아이오아이가, f=18, s=0.22 #c 1:4 #c 1 = #c 1:2 #c 1 #c 1:3 #c 1:2 #c 1:4 #c 1:3 단어로선택 20
Cohesion (Character n-gram) 단어의점수 (cohesion) 를아래처럼구현해봅니다 def cohesion(w): return pow(count[w]/count[w[0]], 1/(len(w)-1)) 아이, 아이오, f=4910, s=0.15 f=307, s=0.10 word = ' 아이오아이가 n = len(word) for e in range(2, n+1): w = word[:e] f = count[w] s = cohesion(w) print('{:6}, f={}, s={:.2}'. format(w, f, s)) 아이오아, 아이오아이, f=270, s=0.20 f=270, s=0.30 아이오아이가, f=18, s=0.22 #c 1:4 #c 1 = #c 1:2 #c 1 #c 1:3 #c 1:2 #c 1:4 #c 1:3 단어로선택 21
Tokenizer 단어를잘인식할수있다면토크나이징도쉽게할수있습니다 토크나이징은여러개의단어로이뤄진문장 / 어절에서단어를구분하는것 띄어쓰기오류정도에따라다른토크나이징전략을사용할수있습니다 22
L-Tokenizer 띄어쓰기가잘되어있다면, 어절의왼쪽에서부터 단어의점수가가장큰 subword 를기준으로어절을나눕니다 def ltokenize(w): n = len(w) if n <= 2: return (w, '') tokens = [] for e in range(2, n+1): tokens.append(w[:e], w[e:], cohesion(w[:e])) tokens = sorted(tokens, key=lambda x:-x[2]) return tokens[0][:2] (' 뉴스 ', ' 의 ') (' 기사 ', ' 를 ') (' 이용 ', ' 했던 ') (' 예시 ', ' 입니다 ') sent = 뉴스의기사를이용했던예시입니다 ' for word in sent.split(): print( ltokenize(word) ) 23
Max Score Tokenizer 띄어쓰기가잘되어있지않다면아는단어부터잘라내면됩니다 cohesions = {' 파스 ': 0.3, ' 파스타 ': 0.7, ' 좋아요 ': 0.2, ' 좋아 ':0.5} score = lambda x: cohesions.get(x, 0) tokenize(' 파스타가좋아요 ') [(' 파스 ', 0, 2, 0.3), (' 파스타 ', 0, 3, 0.7), (' 스타 ', 1, 3, 0), (' 스타가 ', 1, 4, 0), (' 타가 ', 2, 4, 0), (' 타가좋 ', 2, 5, 0), (' 가좋 ', 3, 5, 0), (' 가좋아 ', 3, 6, 0), (' 좋아 ', 4, 6, 0.5), (' 좋아요 ', 4, 7, 0.2), (' 아요 ', 5, 7, 0)] [(' 파스타 ', 0, 3, 0.7), (' 좋아 ', 4, 6, 0.5), (' 파스 ', 0, 2, 0.3), (' 좋아요 ', 4, 7, 0.2), (' 스타 ', 1, 3, 0), (' 스타가 ', 1, 4, 0), (' 타가 ', 2, 4, 0), (' 타가좋 ', 2, 5, 0), (' 가좋 ', 3, 5, 0), (' 가좋아 ', 3, 6, 0), (' 아요 ', 5, 7, 0)] [(' 파스타 ', 0, 3, 0.7), (' 좋아 ', 4, 6, 0.5), (' 파스 ', 0, 2, 0.3), (' 좋아요 ', 4, 7, 0.2), (' 스타 ', 1, 3, 0), (' 스타가 ', 1, 4, 0), (' 타가 ', 2, 4, 0), (' 타가좋 ', 2, 5, 0), (' 가좋 ', 3, 5, 0), (' 가좋아 ', 3, 6, 0), (' 아요 ', 5, 7, 0)] Subword 별 score 계산 (subword, begin, end, score) Score 기준으로정렬최고점수의단어선택, 위치가겹치는단어제거 24
Max Score Tokenizer 띄어쓰기가잘되어있지않다면아는단어부터잘라내면됩니다 cohesions = {' 파스 ': 0.3, ' 파스타 ': 0.7, ' 좋아요 ': 0.2, ' 좋아 ':0.5} score = lambda x: cohesions.get(x, 0) [ 파스타 ] 가좋아요 [ 파스타 ] 가 [ 좋아 ] 요 [(' 파스타 ', 0, 3, 0.7), (' 좋아 ', 4, 6, 0.5), (' 파스 ', 0, 2, 0.3), (' 좋아요 ', 4, 7, 0.2), (' 스타 ', 1, 3, 0), (' 스타가 ', 1, 4, 0), (' 타가 ', 2, 4, 0), (' 타가좋 ', 2, 5, 0), (' 가좋 ', 3, 5, 0), (' 가좋아 ', 3, 6, 0), (' 아요 ', 5, 7, 0)] [(' 파스타 ', 0, 3, 0.7), (' 좋아 ', 4, 6, 0.5), (' 파스 ', 0, 2, 0.3), (' 좋아요 ', 4, 7, 0.2), (' 스타 ', 1, 3, 0), (' 스타가 ', 1, 4, 0), (' 타가 ', 2, 4, 0), (' 타가좋 ', 2, 5, 0), (' 가좋 ', 3, 5, 0), (' 가좋아 ', 3, 6, 0), (' 아요 ', 5, 7, 0)] [ 파스타, 가, 좋아, 요 ] 25
Max Score Tokenizer 확실히아는단어라면 scores 에최고점수를줄수있습니다 cohesions = {' 파스 ': 0.3, ' 파스타 ': 0.7, ' 좋아요 ': 0.2, ' 좋아 ':0.5, 아이오아이 :1.0} score = lambda x:cohesions.get(x, 0) 26
soynlp Cohesion, Branching Entropy 를포함한, 단어추출에관련된함수들을 github 에구현해두었습니다. from soynlp import DoublespaceLineCorpus from soynlp.word import WordExtractor corpus = DoublespaceLineCorpus(fname, iter_sent=true) word_extractor = WordExtractor(corpus, min_count=10) words = word_extractor.extract() 27
soynlp extract() 는단어경계와관련된점수들이계산되어있는 dict를 return 합니다 words = word_extractor.extract() words[ 드라마 '] Scores(cohesion_forward=0.6093651029086764, cohesion_backward=0.5282705437953743, left_branching_entropy=3.6583115265560924, right_branching_entropy=3.675624807575614, left_accessor_variety=128, right_accessor_variety=136, leftside_frequency=2375, rightside_frequency=1284) 28
soynlp Tokenizer 역시구현되어있습니다 from soynlp.tokenizer import LTokenizer scores = {w:s.cohesion_forward for w, s in words.items()} tokenizer = LTokenizer(scores=scores) tokenizer.tokenize( 뉴스의기사를이용했던예시입니다 ') [ 뉴스, 의, 기사, 를, 이용, 했던, 예시, 입니다 ] 29
soynlp 사전이없이도데이터기반으로토크나이저를학습하면잘작동합니다 현재분석중인데이터에해당알고리즘을적용한예시입니다 from soynlp.tokenizer import MaxScoreTokenizer scores = {w:s.cohesion_forward for w, s in words.items()} tokenizer = MaxScoreTokenizer(scores=scores) tokenizer.tokenize( 맛있는짜파게티파스타일식초밥소바김볶다먹고싶어라일단김밥천국으로고고 ') [' 맛있 ', ' 는 ', ' 짜파게티 ', ' 파스타 ', ' 일식 ', ' 초밥 ', ' 소바 ', ' 김볶 ', ' 다 ', ' 먹고 ', ' 싶어 ', ' 라 ', ' 일단 ', ' 김밥천국 ', ' 으로 ', ' 고고 '] 30
명사추출 https://github.com/lovit/soynlp 31
명사 지금까지분석할데이터를기반으로, 그데이터에서사용되는 단어를추출하는방법을이야기했습니다 이번에는 { 파스타, 좋아 } 와같은단어에서 파스타 라는명사만선택하는 방법을알아봅니다 32
A 는명사일까? 어제 A 라는가게에가봤어 A 에서보자 A 로와줘 명사우측에등장하는글자분포를이용하여 A 가명사임을유추할수있다 33
L R graph 어절은 L + [R] 구조로나눌수있습니다 발표 + 를 하 + 면서 데이터에서모든어절들을두개의 subwords 로나눈뒤연결하면 L R graph 를만들수있습니다 34
L R graph L 드라마 frequency ( 드라마 를 ) 를 R 파이콘 의 발표 로 파이 에서 콘에서 시작했 지마 먹 었어 고서 달리 35
L R graph 드라마파이콘발표파이 를의로에서 명사들의오른쪽에는 콘에서 시작했지마조사들이주로연결되어있습니다 었어먹고서달리 36
L R graph 드라마 동사 / 형용사들의오른쪽에는 를어미들이파이콘주로연결되어있습니다의 발표파이 시작했먹달리 로에서콘에서 지마었어고서 37
L R graph 드라마 L 이제대로된단어가아니면 를오른쪽에도파이콘조사 / 어미가아닌 R이연결됩니다의 발표파이 시작했먹달리 로에서콘에서 지마었어고서 38
Noun Extraction L R graph 를만들면명사가눈에보입니다 lrgraph = defaultdict(lambda: defaultdict(lambda: 0)) for doc in docs: for w in doc.split(): n = len(w) for e in range(1, n+1): lrgraph[ w[ :e] ][ w[e: ] ] += 1 def get_r(l): return sorted( lrgraph[l].items(), key=lambda x:-x[1]) get_r( 드라마 ) [('', 1268), (' 를 ', 164), (' 다 ', 152), (' 의 ', 140), (' 로 ', 138), (' 에서 ', 98), (' 와 ', 62), (' 는 ', 55), (' 에 ', 55), (' 가 ', 48), (' 이다 ', 24), (' 인 ', 14), ] 39
Noun Extraction L R graph: [ 명사 + 조사 ], [ 동사 + 어미 ], [ 틀린단어 + 틀린단어 ] get_r( 드라마 ') get_r(' 시작했 ') get_r(' 드라 ') [('', 1268), [(' 다 ', 567), [(' 마 ', 1268), (' 를 ', 164), (' 고 ', 73), (' 마를 ', 164), (' 다 ', 152), (' 다고 ', 61), (' 마다 ', 152), (' 의 ', 140), (' 습니다 ', 42), (' 마의 ', 140), (' 로 ', 138), (' 는데 ', 26), (' 마로 ', 138), (' 에서 ', 98), (' 으며 ', 16), (' 마에서 ', 98), (' 와 ', 62), (' 지만 ', 15), (' 기 ', 65), (' 는 ', 55), (' 던 ', 12), (' 마와 ', 62), (' 에 ', 55), (' 어요 ', 10), (' 마는 ', 55), (' 가 ', 48), (' 다는 ', 7), (' 마에 ', 55), (' 이다 ', 24), (' 으나 ', 5), (' 마가 ', 48), (' 인 ', 14), (' 죠 ', 4), (' 이브 ', 28), ] ] ] 40
Noun Extraction L R graph: [ 명사 + 조사 ], [ 동사 + 어미 ], [ 틀린단어 + 틀린단어 ] get_r(' 드라마 ') get_r(' 시작했 ') get_r(' 드라 ') [('', 1268), [(' 다 ', 567), [(' 마 ', 1268), (' 를 ', 164), (' 고 ', 73), (' 마를 ', 164), (' 다 ', 152), (' 다고 ', 61), (' 마다 ', 152), (' 의 ', 140), (' 습니다 ', 42), (' 마의 ', 140), (' 로 ', 138), (' 는데 ', 26), (' 마로 ', 138), (' 에서 ', 98), (' 으며 ', 16), (' 마에서 ', 98), (' 와 ', 62), (' 지만 ', 15), (' 기 ', 65), (' 는 ', 55), (' 던 ', 12), (' 마와 ', 62), (' 에 ', 55), (' 어요 ', 10), (' 마는 ', 55), (' 가 ', 48), (' 다는 ', 7), (' 마에 ', 55), (' 이다 ', 24), (' 으나 ', 5), (' 마가 ', 48), (' 인 ', 14), (' 죠 ', 4), (' 이브 ', 28), ] ] ] 41
Noun Extraction L R graph: [ 명사 + 조사 ], [ 동사 + 어미 ], [ 틀린단어 + 틀린단어 ] get_r(' 드라마 ') get_r(' 시작했 ') get_r(' 드라 ') [('', 1268), [(' 다 ', 567), [(' 마 ', 1268), (' 를 ', 164), (' 고 ', 73), (' 마를 ', 164), (' 다 ', 152), (' 다고 ', 61), (' 마다 ', 152), (' 의 ', 140), (' 습니다 ', 42), (' 마의 ', 140), (' 로 ', 138), (' 는데 ', 26), (' 마로 ', 138), (' 에서 ', 98), (' 으며 ', 16), (' 마에서 ', 98), (' 와 ', 62), (' 지만 ', 15), (' 기 ', 65), (' 는 ', 55), (' 던 ', 12), (' 마와 ', 62), (' 에 ', 55), (' 어요 ', 10), (' 마는 ', 55), (' 가 ', 48), (' 다는 ', 7), (' 마에 ', 55), (' 이다 ', 24), (' 으나 ', 5), (' 마가 ', 48), (' 인 ', 14), (' 죠 ', 4), (' 이브 ', 28), ] ] ] 42
Noun Extraction R 의분포를이용하여 L 의명사점수를계산할수있습니다 r_scores = {' 은 ': 0.5, 었다 ': -0.9, } def noun_score(l): (norm, score, _total) = (0, 0, 0) for R, frequency in get_r(l): _total += frequency if not R in r_scores: continue norm += frequency score += frequency * r_scores[r] score = score / norm if norm else 0 prop = norm / _total if _total else 0 return score, prop S L l = f l, r S R(r) r L R f(l, r) 드라마 를 (164) 다 (152) 의 (140) 로 (138) 에서 (98) 와 (62) 43
Noun Extraction R 의분포를이용하여 L 의명사점수를계산할수있습니다 ( 명사점수, 알려진 R 비율 ) = noun_score( Word ) noun_score(' 드라마 ) (0.574, 0.921) noun_score( 시작했 ) (-0.976, 0.999) noun_score( 드라 ) (-0.661, 0.579) 틀린단어뒤에는조사 / 어미들이아닌글자들이등장 44
Noun Extraction R 점수는세종말뭉치를이용하여계산합니다 세종말뭉치의품사가태깅된정보로부터 L R 구조의테이블을만듭니다... 예술가의예술가 /NNG+ 의 /JKG 113 예술가는예술가 /NNG+ 는 /JX 45 예술가가예술가 /NNG+ 가 /JKS 43 예술가들의예술가 /NNG+ 들 /XSN+ 의 /JKG 30... 단어품사명사동사 단어 / R - 는 - 의 - 고 - 었다 -었던 예술가 45 113 2 0 0 먹 33 0 27 0 27 45
Noun Extraction 명사의빈도를고려하여 R 앞에명사가등장할점수를계산합니다 품사명사명사동사형용사 단어 / R - 는 - 의 - 고 - 었다 -구나 예술가 45 113 2 0 0 나이 54 87 27 0 27 들 0 0 0 255 0 춥 0 0 0 0 87 품사빈도수 ( 비율 ) 명사 704,197 (0.838) 품사빈도수보정빈도수점수 명사 980 980 0.810 ^ 명사 136,598 (0.162) ^명사 20 103.5 = 20 * (0.838/0.162) = (980 103.5) / (980 + 103.5) 46
soynlp 후처리과정이추가된명사추출기를구현하였습니다 from soynlp.noun import LRNounExtractor noun_extractor = LRNounExtractor(min_count=50) nouns = noun_extractor.train_extract(corpus, minimum_noun_score=0.5) nouns[ 설입 ] NounScore(frequency=67, score=0.926, known_r_ratio=0.529) nouns[ 드라마 ] NounScore(frequency=4976, score=0.522, known_r_ratio=0.601) 47
KoNLPy + 사용자사전 https://github.com/lovit/customized_konlpy 48
사용자사전 + 템플릿매칭을이용한토크나이징 / 품사판별 명사 / 단어에대해서사용자사전을만든다면, 내가임의의템플릿을 만들어서템플릿매칭으로아는단어들을처리할수도있습니다 custom_dictionary = {'Noun': [ 파이콘 ', ' 엔엘피 ', ' 아이오아이 ', ' 너무너무너무 ']} templates = [('Noun', 'Noun'), ('Noun', 'Josa'), ('Noun', 'Noun', Josa')] 49
사용자사전 + 템플릿매칭을이용한토크나이징 / 품사판별 custom_dictionary = {'Noun': [' 파이콘 ', ' 엔엘피 ', ' 아이오아이 ', ' 너무너무너무 ']} templates = [('Noun', 'Noun'), ('Noun', 'Josa'), ('Noun', 'Noun', Josa')] [ 파이콘 ][ 에서 ] [ 엔엘피 ][ 이야기 ][ 를 ] 합시다 (Noun, Josa) (Noun, Noun, Josa) Unknown KoNLPy 에넘기자 * 빨간색은사용자에의하여추가된사전에서매칭 * 파란색은 KoNLPy 의트위터분석기에포함되어있는사전에서매칭 50
사용자사전 + 템플릿매칭을이용한토크나이징 / 품사판별 customized_konlpy 에사전 / 템플릿추가를쉽게할수있도록 KoNLPy 를 래핑해두었습니다 from ckonlpy.tag import Twitter tagger = Twitter() tagger.add_dictionary([' 파이콘 ', ' 엔엘피 ', ' 아이오아이 ', ' 너무너무너무 '], 'Noun') tagger.pos(' 파이콘에서엔엘피이야기를합시다 ') tagger.pos(' 너무너무너무는아이오아이의노래에요 ') [(' 파이콘 ', 'Noun'), (' 에서 ', Josa'), (' 엔엘피 ', 'Noun'), (' 이야기 ', 'Noun'), (' 를 ', 'Josa'), (' 합 ', 'Verb'), (' 시 ', 'PreEomi'), (' 다 ', 'Eomi')] [(' 너무너무너무 ', 'Noun'), (' 는 ', 'Josa'), (' 아이오아이 ', 'Noun'), (' 의 ', 'Josa'), (' 노래 ', 'Noun'), (' 에요 ', 'Josa')] 51
정리 데이터기반으로스스로단어 / 명사를추출하고, 이를그대로이용하거나 KoNLPy 와결합하여텍스트를처리하는방법에대하여이야기하였습니다 아직도좀더좋은단어 / 명사추출기와토크나이저를연구하고있습니다 조금더편한데이터분석을, 분석준비가아닌분석에더많이집중하는데 도움이되었으면좋겠습니다 52