rueki

텍스트 전처리 - 토큰화(Tokenization) 본문

DL/NLP

텍스트 전처리 - 토큰화(Tokenization)

륵기 2019. 7. 1. 10:59
728x90
반응형

본문은 https://wikidocs.net/22592 를 참고해서 작성한 글입니다.

 

기계가 Text를 이해하도록 하기위해서는 텍스트 정제를 해주어야하는데

이에 앞어 텍스트 전처리를 말해보도록 하겠다.

1. 토큰화

2. 정규화

3. 어근화 / 어근 추출 및 표제어 추출

4. 불용어

5. 정규표현식

현재로서는 5가지로 나누어봤지만 그 외의 방법도 엄청 많다는 것을 찾아보면서 발견했다.

그래서 이번 게시글에서는 토큰화만 다루어보겠다.

 


토큰화(Tokenization)

 

 

 

위의 예시는 띄어쓰기를 기준으로 토근화 했지만 한국어 문장의 경우에 위와 같이 토큰화를 진행했을 때

단어 토큰을 구분하기 힘들 것이다.

 


 

한국어에는 '어절'이라는 띄어쓰기 단위가 있는데 어절 토큰화와 단어 토큰화가 같지가 않다.

영어와 다르게 한국어는 독립적인 단어로만 구성되있지 않기에 형태소라는 개념을 인지해야 한다.

 

형태소(morpheme) :  의미를 가지는 요소로서는 더 이상 분석할 수 없는 가장 작은 말의 단위

자립형태소 : 다른 말의 도움 없이 그것만으로도 자립할 수 있는 형태소. 

                 체언(명사, 대명사, 수사), 수식언(관형사, 부사), 감탄사 등이 있다.

의존형태소 :  다른 형태소와 결합하여 사용되는 형태소. 접사, 어미, 조사, 어간를 말한다.

 

Ex) 나는 공부를 한다.

자립 형태소 : 나, 공부

의존 형태소 :  -는, -를, 한-, -다

 

이를 통해 영어의 단어 토큰화와 비슷한 형태를 얻으려면 형태소 토큰화를 진행해야한다는 것을 알 수가 있다.

 


이에 앞서 토큰화 과정에서 영어 문장에서의 고려사항을 알아보자.

Ex) Don't bothering me, I don't want to kill you.

 

위의 문장을 NLTK(영어 코퍼스를 토큰화 하기위한 도구)를 사용해서 진행해보자.

import nltk
from nltk.tokenize import word_tokenize
nltk.download('punkt') // nltk 패키지 다운로드
print(word_tokenize("Don't bothering me. i want to kill you."))
['Do', "n't", 'bothering', 'me', '.', 'i', 'want', 'to', 'kill', 'you', '.']

word_tokenize는 Don't 를 'Do', "n't" 로 분리한 것을 확인할 수 있었다.

from nltk.tokenize import WordPunctTokenizer
print(WordPunctTokenizer().tokenize("Don't bothering me. i want to kill you."))
['Don', "'", 't', 'bothering', 'me', '.', 'i', 'want', 'to', 'kill', 'you', '.']

WordPunctTokenizer에서는 Don, " ' ", 't' 로 분리되었다.

구두점을 별도 분리하기때문에 Word_tokenize와는 다른 결과가 나온 것을 확인할 수 있었다.


토큰화 할 때 고려사항으로 아래의 2가지 사항이 있다.

1. 구두점 및 특수문자 제외 X

    Ex) Ph.D, M&M

2. 줄임말 및 단어 내 띄어쓰기 

    Ex) We are -> We're

 

이를 위해 표준 토큰화를 Treebank Tokenization을 통해 알아보자

from nltk.tokenize import TreebankWordTokenizer
tokenizer = TreebankWordTokenizer()
text = "It doesn't matter. AT&T is the best company in USA."
tokenizer.tokenize(text)
['It',
 'does',
 "n't",
 'matter.',
 'AT',
 '&',
 'T',
 'is',
 'the',
 'best',
 'company',
 'in',
 'USA',
 '.']

doesn't -> does, n't

AT&T -> AT, & , T ==> &(특수문자) 제거 X

 

위와 같은 결과를 통해 아포스트로피가 들어가는 단어는 분리가 되며 특수문자는 제거되지 않는 것을 확인할 수 있다.


문장 토큰화

토큰의 단위가 문장일 때는 토큰화를 어떻게 수행해야 할까?

문장 단위로 분류되지 않았을 때, 토큰화가 필요한데 여기서도 토큰화의 기준은 필요하다.

예를 들어 "I'm Ph.d." 라는 문장이 있을 때, 온점을 기준으로 토큰화가 이루어지면 문장 토큰화가 이루어지지 않는다.

 

NLTK의 sent_tokenize는 영어에 있어 문장 분류를 해준다.

from nltk.tokenize import sent_tokenize
text = "She is very pretty, but I don't want to marry with her. because, She is so lazy."
print(sent_tokenize(text))
["She is very pretty, but I don't want to marry with her.", 'because, She is so lazy.']

문장 구분이 제대로 이루어진 것을 확인할 수 있었다.


품사 태깅(Part-of-speech tagging)

단어는 품사에 따라서 의미가 달라질 수도 있다. 예를들어 Fly는 명사로 파리, 동사로 날다라는 뜻이 있다.

그래서 의미를 상황에 맞게 제대로 파악하기 위해서는 품사가 무엇인지가 중요하다.

토큰화 과정에서 품사 구분을 하는 작업을 품사 태깅이라고 한다.

 

from nltk.tag import pos_tag
#nltk.download('averaged_perceptron_tagger')
print(pos_tag(text))
[('S', 'NNP'), ('h', 'NN'), ('e', 'NN'), (' ', 'NNP'), ('i', 'NN'), 
('s', 'VBP'), (' ', 'JJ'), ('v', 'NN'), ('e', 'NN'), ('r', 'NN'), ('y', 'NN'), 
(' ', 'NNP'), ('p', 'NN'), ('r', 'NN'), ('e', 'NN'), ('t', 'NN'), ('t', 'NN'), 
('y', 'NN'), (',', ','), (' ', 'NNP'), ('b', 'NN'), ('u', 'NN'), ('t', 'NN'), 
(' ', 'NN'), ('I', 'PRP'), (' ', 'VBP'), ('d', 'JJ'), ('o', 'IN'), ('n', 'JJ'), 
("'", 'POS'), ('t', 'NN'), (' ', 'NNP'), ('w', 'VBZ'), ('a', 'DT'), ('n', 'JJ'), 
('t', 'NN'), (' ', 'NNP'), ('t', 'NN'), ('o', 'NN'), (' ', 'NNP'), ('m', 'VBZ'), 
('a', 'DT'), ('r', 'NN'), ('r', 'NN'), ('y', 'NN'), (' ', 'NNP'), ('w', 'NN'), 
('i', 'NN'), ('t', 'VBP'), ('h', 'NN'), (' ', 'NN'), ('h', 'NN'), ('e', 'NN'), 
('r', 'NN'), ('.', '.'), (' ', 'NN'), ('b', 'NN'), ('e', 'NN'), ('c', 'VBZ'), 
('a', 'DT'), ('u', 'JJ'), ('s', 'NN'), ('e', 'NN'), (',', ','), (' ', 'NNP'), 
('S', 'NNP'), ('h', 'NN'), ('e', 'NN'), (' ', 'NNP'), ('i', 'NN'), ('s', 'VBP'), 
(' ', 'JJ'), ('s', 'NN'), ('o', 'NN'), (' ', 'NNP'), ('l', 'VBZ'), ('a', 'DT'), 
('z', 'NN'), ('y', 'NN'), ('.', '.')]

"She is very pretty, but I don't want to marry with her. because, She is so lazy." 라는 문장을

단어토큰화를 시키지 않아서 모든 스펠링에 대한 품사가 나와버렸다.

x = word_tokenize(text)
print(pos_tag(x))
[('She', 'PRP'), ('is', 'VBZ'), ('very', 'RB'), ('pretty', 'RB'), 
(',', ','), ('but', 'CC'), ('I', 'PRP'), ('do', 'VBP'), ("n't", 'RB'), 
('want', 'VB'), ('to', 'TO'), ('marry', 'VB'), ('with', 'IN'), ('her', 'PRP'), 
('.', '.'), ('because', 'IN'), (',', ','), ('She', 'PRP'), ('is', 'VBZ'), 
('so', 'RB'), ('lazy', 'JJ'), ('.', '.')]

VBP = 동사, RB = 부사, VBG = 현재부사, IN = 전치사, NPP = 고유명사, NNS = 복수형 명사

CC = 접속사, DT = 관사

각 단어마다 품사가 토큰화 된 것을 볼 수 있었다.

 

다음은 KoNLpy를 통한 한국어 처리를 해보자.

형태소 분석에는 Okt(Open korea Text), Mecab, Komoran 등이 있다.

 

from konlpy.tag import Okt
okt = Okt()
print(okt.morphs("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
#형태소 분리

 

['코딩', '하느라', '고생', '이', '많습니다', '.', '조금', '만', '더', '고생', '해주세요', '.']

품사 태깅을 한 번 진행해보자

print(okt.pos("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
[('코딩', 'Noun'), ('하느라', 'Verb'), ('고생', 'Noun'), ('이', 'Josa'), 
('많습니다', 'Adjective'), ('.', 'Punctuation'), ('조금', 'Noun'), ('만', 'Josa'), ('더', 'Noun'), ('고생', 'Noun'), 
('해주세요', 'Verb'), ('.', 'Punctuation')]

명사만 따로 추출해보자

print(okt.nouns("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
['코딩', '고생', '조금', '더', '고생']

형태소 분석기마다 조금씩 기능이 다른데 꼬꼬마 분석기로 한 번 진행해보자.

from konlpy.tag import Kkma
kkma = Kkma()
print(kkma.morphs("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
['코딩', '하', '느라', '고생', '이', '많', '습니다', '.', '조금', '만', '더', '고생', '하', '어', '주', '세요', '.']

 

print(kkma.pos("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
[('코딩', 'NNG'), ('하', 'XSV'), ('느라', 'ECD'), ('고생', 'NNG'), ('이', 'JKS'), 
('많', 'VA'), ('습니다', 'EFN'), ('.', 'SF'), ('조금', 'NNG'), ('만', 'JX'), 
('더', 'MAG'), ('고생', 'NNG'), ('하', 'XSV'), ('어', 'ECS'), ('주', 'VXV'), ('세요', 'EFN'), ('.', 'SF')]

 

print(kkma.nouns("코딩하느라 고생이 많습니다. 조금만 더 고생해주세요."))
['코딩', '고생', '조금']

 

728x90
반응형
Comments