1. 단어 토큰화
토큰의 기준을 단어(word)로 하는 경우, 단어 토큰화(word tokenization)라고 한다. 다만, 여기서 단어(word)는 단어 단위 외에도 단어 구, 의미를 갖는 문자열로도 간주되기도 한다.
예를 들어보면, 구두점(punctuation)과 같은 문자는 제외시키는 간단한 단어 토큰화를 해보자.
*구두점이란, 온점(.), 컴마(,), 물음표(?), 세미콜론(;), 느낌표(!) 등과 같은 기호를 말한다.
입력:Time is an illusion. Lunchtime double so!
이러한 입력으로 구두점을 제외 시킨 토큰화 작업을 한 결과는 다음과 같다.
출력 : "Time", "is", "an", "illustion", "Lunchtime", "double", "so"
이 예제에서 토큰화 작업은 굉장히 간단하다. 구두점을 지운 뒤에 띄어쓰기(whitespace)를 기준으로 자른 것이다.
보통 토큰화 작업은 단순히 구두점이나 특수문자를 전부 제거하는 정제(cleaning) 작업을 수행하는 것만으로 해결되지 않는다. 구두점이나 특수문자를 전부 제거하면 토큰이 의미를 잃어버리는 경우가 발생하기도 한다다. 심지어 띄어쓰기 단위로 자르면 사실상 단어 토큰이 구분되는 영어와 달리, 한국어는 띄어쓰기만으로는 단어 토큰을 구분하기 어렵다. 그 이유는 뒤에서 알아볼 것이다.
2. 토큰화 중 생기는 선택의 순간
토큰화를 하다 보면, 예상하지 못한 경우들이 발생한다. 예를 들어 영어권 언어에서 아포스트로피를(')가 들어가 있는 단어는 어떻게 토큰으로 분류해야 할까라는 문제를 알아보자.
예: Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop.
여기서 Don't와 Jone's는 어떻게 토큰 화할 수 있을까?
- Don't
- Don t
- Dont
-
Do n't
-
Jone's
- Jone s
- Jone
- Jones
원하는 결과가 나오도록 토큰화 도구를 집적 설계할 수 있지만, 기존에 공개된 도구와 사용자의 목적이 일치하면 해당 도구를 사용한다. NLTK는 영어 코퍼스를 토큰화 하기 위한 도구 들으 제공한다. 그중 word_tokenize와 WordPunctTokenizer를 사용해서 NLTK에서는 아포스트로피를 어떻게 처리하는지 알아보자.
from nltk.tokenize import word_tokenize
print(word_tokenize("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery
as cheery goes for a pastry shop."))
['Do', "n't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', ',', 'Mr.', 'Jone', "'s",
'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop', '.']
word_tokenize는 Don't를 Do와 n't로 분리하였으며, 반면 Jone's는 Jone과 's로 분리한 것을 확인할 수 있다.
그렇다면, wordPunctTokenizer는 아포스트로피가 들어간 코퍼스를 어떻게 처리할까?
from nltk.tokenize import WordPunctTokenizer
print(WordPunctTokenizer().tokenize("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage
is as cheery as cheery goes for a pastry shop."))
['Don', "'", 't', 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', ',', 'Mr', '.', 'Jone',
"'", 's', 'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry',
'shop', '.']
WordPunctTokenizer는 구두점을 별도로 분류하는 특징을 갖고 있기 때문에, 앞서 확인했던 word_tokenize와는 달리 Don't를 Don과 '와 t로 분리하였으며, 이와 마찬가지로 Jone's를 Jone과 '와 s로 분리한 것을 확인할 수 있다.
케라스(keras) 또한 토큰화 도구로서 text_to_word_sequence를 지원한다. 이번에는 케라스로 토큰화를 수행해보자.
from tensorflow.keras.preprocessing.text import text_to_word_sequence
print(text_to_word_sequence("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as
cheery as cheery goes for a pastry shop."))
["don't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', 'mr', "jone's", 'orphanage',
'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop']
케라스의 text_to_word_sequence는 기본적으로 모든 알파벳을 소문자로 바꾸면서 온점이나 컴마, 느낌표 등의 구두점을 제거한다. 하지만 don't나 jone's와 같은 경우 아포스트로피는 보존하는 것을 볼 수 있다.
3. 토큰화에서 고려해야 할 사항
토큰화 작업을 단순하게 코퍼스에서 구두점을 제외하고 공백 기준으로 잘라내는 작업이라고 간주할 수는 없다.
1) 구두점이나 특수 문자를 단순 제외해서는 안된다.
구두점이나 특수 문자를 단순히 제외하는 것은 옳지 않다. 코퍼스에서 정제 작업을 하다 보면, 구두점조차도 하나의 토큰으로 분류한다. 예를 들어 온점과 같은 문장 같은 경우는 문장의 경계를 알 수 있는데 도움이 되므로 단어를 뽑아낼 때, 온점(.)을 제외하지 않을 수 있다. 숫자 사이에 컴마(,)가 들어가는 경우도 있다.
2) 줄임말과 단어 내에 띄어쓰기가 있는 경우.
what're는 what are의 줄임말이며, we're는 we are의 줄임말이다. 위의 예에서 re를 접어(clitic)이라고 한다. 즉, 단어가 줄임말로 쓰일 때 생기는 형태를 말한다. 가령 I am을 줄인 I'm이 있을 때, m을 접어라고 한다.
3) 표준 토큰화 예제
표준으로 쓰이고 있는 토큰화 방법 중 하나인 Penn Treebank Tokenization의 규칙에 대해서 소개하고, 토큰화의 결과를 보도록 하겠다.
규칙 1. 하이픈으로 구성된 단어는 하나로 유지한다.
규칙 2. doesn't와 같이 아포스트로피로 '접어'가 함께하는 단어는 분리해준다.
예: "Starting a home-based restaurant may be an ideal. it doesn't have a food chain or restaurant of their own."
from nltk.tokenize import TreebankWordTokenizer
tokenizer=TreebankWordTokenizer()
text="Starting a home-based restaurant may be an ideal. it doesn't have a food chain or rest
aurant of their own."
print(tokenizer.tokenize(text))
['Starting', 'a', 'home-based', 'restaurant', 'may', 'be', 'an', 'ideal.', 'it', 'does', "n't", '
have', 'a', 'food', 'chain', 'or', 'restaurant', 'of', 'their', 'own', '.']
결과를 보면, 각각 규칙 1과 규칙 2에 따라서 home-based는 하나의 토큰으로 취급하고 있으며, dosen't의 경우 does와 n't는 분리되었음을 볼 수 있다.
4. 문장 토큰화(Sentence Tokenization)
토큰의 단위가 문장(Sentence) 일 때, 어떻게 토큰 화가 되는지 알아보자
코퍼스 내에서 문장 단위로 구분하는 작업으로 때로는 문장 분류(sentence segmentation)라고도 부른다.
? 나 온점(.)이나! 기준으로 문장을 잘라내면 되지 않을까라고 생각할 수 있지만, 꼭 그렇지만은 않다.! 나? 는 문장의 구분을 위한 꽤 명확한 구분자(boundary) 역할을 하지만 온점은 꼭 그렇지 않기 때문이다. 다시 말해, 온점은 문장의 끝이 아니더라도 등장할 수 있다.
NLTK에서는 영어 문장의 토큰화를 수행하는 sent_tokenize를 지원하고 있다. NLTK를 통해 문장 토큰화를 실습해보고, 문장 토큰화에 대해 이해해보도록 해보겠다.
from nltk.tokenize import sent_tokenize
text="His barber kept his word. But keeping such a huge secret to himself was dr
iving him crazy. Finally, the barber went up a mountain and almost to the edge o
f a cliff. He dug a hole in the midst of some reeds. He looked about, to mae sure no
one was near."
print(sent_tokenize(text))
['His barber kept his word.', 'But keeping such a huge secret to himself was driving
him crazy.', 'Finally, the barber went up a mountain and almost to the edge of a
cliff.', 'He dug a hole in the midst of some reeds.', 'He looked about, to mae sure no onewas near.']
위 코드는 text에 저장된 여러 개의 문장들로부터 문장을 구분하는 코드이다. 출력 결과를 보면 성공적으로 모든 문장을 구분해내었음을 볼 수 있다.
이제 중간에 온점이 여러 번 등장하는 경우를 해볼 것이다.
from nltk.tokenize import sent_tokenize
text="I am actively looking for Ph.D. students. and you are a Ph.D student."
print(sent_tokenize(text))
['I am actively looking for Ph.D. students.', 'and you are a Ph.D student.']
NLTK는 단순히 온점을 구분자로 하여 문장을 구분하지 않았기 때문에, Ph.D. 를 문장 내의 단어로 인식하여 성공적으로 인식하는 것을 볼 수 있다.(한국어에 대한 문장 토큰화 도구가 존재한다. KSS(Korean Sentence Splitter)이다.)
5. 품사 태깅(Part-of-speech tagging)
단어는 표기는 같지만, 품사에 따라서 단어의 의미가 달라지기도 한다. 예를 들어서 영어 단어 'fly'는 동사로는 '날다'라는 의미를 갖지만, 명사로는 '파리'라는 의미를 갖고 있다. 한국어도 마찬가지이다. '못'이라는 단어는 명사로서는 망치를 사용해서 목재 따위를 고정하는 물건을 의미한다. 하지만 부사로서의 '못'은 '먹는다', '달린다'와 같은 동작 동사를 할 수 없다는 의미로 쓰인다. 즉, 결국 단어의 의미를 제대로 파악하기 위해서는 해당 단어가 어떤 품사로 쓰였는지 보는 것이 주요 지표가 될 수도 있다. 그에 따라 단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지를 구분해놓기도 하는데, 이 작업을 품사 태깅(part-of-speech tagging)이라고 한다. NLKT와 KoNLPy에서는 품사 태깅이 어떻게 되었는지 알아보자.
NLTK
from nltk.tokenize import word_tokenize
text="I am actively looking for Ph.D. students. and you are a Ph.D. student."
print(word_tokenize(text))
['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are
', 'a', 'Ph.D.', 'student', '.']
from nltk.tag import pos_tag
x=word_tokenize(text)
pos_tag(x)
[('I', 'PRP'), ('am', 'VBP'), ('actively', 'RB'), ('looking', 'VBG'), ('for', 'IN'), ('Ph.D.', 'NNP'), ('students', 'NNS'),
('.', '.'), ('and', 'CC'), ('you', 'PRP'), ('are', 'VBP'), ('a', 'DT'), ('Ph.D.', 'NNP'),
('student', 'NN'), ('.', '.')]
VBP는 동사, RB는 부사, VBG는 현재 부사, IN은 전치사, NNP는 고유 명사, NNS는 복수형 명사, CC는 접속사, DT는 관사를 의미한다.
'머신러닝 > 딥러닝을 이용한 자연어처리 입문' 카테고리의 다른 글
데이터의 분리(Splitting Data) (0) | 2019.11.19 |
---|---|
불용어(Stopword) (0) | 2019.11.11 |
어간 추출(Stemming) and 표제어 추출(Lemmatization) (0) | 2019.11.01 |
정제(Cleaning) 과 정규화(Normalization) (0) | 2019.11.01 |
자연어 처리(NLP)란? (0) | 2019.07.31 |