토큰화
주어진 문장에서 "의미 부여"가 가능한 단위를 찾는다.
예 1)
Machine / learning / methods / including / ANN / have / been / applied / in / compound / activity / prediction / for / a / long / time.
단어 토큰화(Word Tokenization)
토큰의 기준을 단어(Word)로 하는 경우를 단어 토큰화라고 한다. 다만, 여기서 단어는 단어 단위 외에도 의미를 갖는 문자열로 간주되기도 한다. 이러한 단어 토큰화 작업을 수행할 시 구두점(마침표, 컴마, 세미콜론, 느낌표 등)과 같은 문자는 제외시킨다는 특징이 있다.
입력 : Time is an illusion. Lunchtime double so!
이러한 입력으로부터 구두점을 제외시킨 토큰화 작업의 결과는 다음과 같다.
출력 : "Time", "is", "an", "illusion", "Lunchtime", "double", "so"
이 예제에서 토큰화 작업은 구두점을 지운 뒤에 띄어쓰기를 기준으로 잘라냈다.
하지만 보통 토큰화 작업은 단순히 구두점이나 특수문자를 전부 제거하는 정제(cleaning) 작업을 수행하는 것만으로 해결되지 않는다. 구두점이나 특수문자를 전부 제거하면 토큰이 의미를 잃어버리는 경우가 발생하기도 한다. 심지어 띄어쓰기 단위로 자르면 사실상 단어 토큰이 구분되는 영어와 달리, 한국어는 띄어쓰기만으로는 단어 토큰을 구분하기 어렵다.
토큰화 중 생기는 선택의 순간
토큰화를 하다보면, 예상하지 못한 경우가 있어 토큰화의 기준을 생각해봐야 하는 경우가 발생한다.
다음과 같은 문장을 보면
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가 있다. 또한 Keras에서 토큰화 도구로서 text_to_word_sequence를 지원한다.
word_tokenizer
토큰화 결과 : ['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_tokenizer는 Don't를 Do와 n't로 분리하였으며, Jone's는 Jone과 's로 분리한 것을 확인할 수 있다.
WordPunctTokenizer
토큰화 결과 : ['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_tokenizer와는 달리 Don't를 Don과 '와 t로 분리하였으며, 마찬가지로 Jone's를 Jone과 '와 s로 분리한 것을 볼 수 있다.
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']
Keras의 text_to_word_sequence는 기본적으로 모든 알파벳을 소문자로 바꾸면서 구두점을 제거한다. 하지만 don't나 jone's와 같은 경우 어포스트로피는 보존하는 것을 볼 수 있다.
토큰화에서 고려해야 할 상황
구두점이나 특수 문자를 단순 제외해서는 안 된다.
코퍼스에 대한 정제 작업을 진행하다 보면, 구두점조차도 하나의 토큰으로 분류하기도 한다. 가장 기본적인 예를 들자면, 마침표와 같은 경우는 문장의 경계를 알 수 있는데 도움이 되므로 단어를 뽑아낼 때, 마침표는 제외하지 않을 수 있다.
또 다른 예로 단어 자체에 구두점을 갖고 있는 경우도 있는데 Ph.D나 AT&T 같은 경우가 있다. 또 특수 문자의 달러나 슬래시의 경우를 들며, $45.55와 같은 가격을 의미하기도 하고, 01/02/06은 날짜를 의미하기도 한다.
줄임말과 단어 내에 띄어쓰기가 있는 경우
토큰화 작업에서 종종 영어권 언어의 어포스트로피는 압축된 단어를 다시 펼치는 역할을 하기도 한다. 예를 들어 what're는 what are의 줄임말이다. 또한 New York이라는 단어를 보면 하나의 단어이지만 중간에 띄어쓰기가 존재한다.
사용 용도에 따라서, 하나의 단어 사이에 띄어쓰기가 있는 경우에도 하나의 토큰으로 봐야하는 경우도 있을 수 있으므로, 토큰화 작업은 저러한 단어를 하나로 인식할 수 있는 능력을 가져야 한다.
TreebankWordTokenizer - 표준 토큰화 예제
규칙 1. 하이푼으로 구성된 단어는 하나로 유지한다.
규칙 2. doesn't와 같이 어포스트로피로 '접어'가 함께 하는 단어는 분리해준다.
토큰화 결과 : ['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는 하나의 토큰으로 취급하고 있으며, doesn't의 경우 does와 n't로 분리되었음을 확인할 수 있다.
문장 토큰화(Sentence Tokenization)
가지고 있는 코퍼스 내에서 문장 단위로 구분하는 작업으로 때로는 문장 분류(Sentence Segmentation)이라고도 부른다. 보통 가지고 있는 코퍼스가 정제되지 않은 상태라면, 코퍼스는 문장 단위로 구분되어 있지 않아 이를 사용하고자 하는 용도에 맞게 문장 토큰화가 필요할 수 있다.
sent_tokenize - 영어 문장 토큰화
NLTK에서는 영어 문장의 토큰화를 수행하는 sent_tokenizer를 지원하고 있다.
토큰화 결과 : ['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 make sure no one was near.']
위 코드는 text에 저장된 여러 개의 문장들로부터 문장을 구분하는 코드이다. 출력 결과를 보면 성공적으로 모든 문장을 구분해내었음을 확인할 수 있다.
토큰화 결과 : ['I am actively looking for Ph.D. students.', 'and you are a Ph.D student.']
NLTK는 단순히 마침표를 구분자로 해 문장을 구분하지 않았기 때문에, 위 코드의 text처럼 문장 중간에 마침표가 다수 등장하는 경우 Ph.D.를 문장 내의 단어로 성공적으로 인식한 것을 볼 수 있다.
kss - 한국어 문장 토큰화
한국어에 대한 문장 토큰화 도구 또한 존재한다. 「딥러닝을 이용한 자연어 처리 입문」에 따르면 KSS(Korean Sentence Splitter)를 추천한다.
토큰화 결과 : ['딥 러닝 자연어 처리가 재미있기는 합니다.', '그런데 문제는 영어보다 한국어로 할 때 너무 어렵습니다.']
출력 결과는 정상적으로 모든 문장이 분리된 결과를 보여준다.
한국어에서의 토큰화의 어려움
영어는 New York과 같은 합성어나 he's와 같이 줄임말에 대한 예외처리만 한다면, 띄어쓰기를 기준으로 하는 토큰화를 수행해도 단어 토큰화가 잘 작동한다. 이것은 거의 대부분의 경우에서 단어 단위의 띄어쓰기가 이루어지기 때문에 띄어쓰기 토큰화와 단어 토큰화가 거의 같기 때문이다.
하지만 한국어는 영어와 달리 띄어쓰기만으로는 토큰화를 하기에 부족하다. 한국어의 경우에는 띄어쓰기 단위가 되는 단위를 '어절'이라고 하는데 어절 토큰화는 한국어 NLP에서 지양되고 있다. 어절 토큰화와 단어 토큰화는 같지 않기 때문이다. 그 근본적인 이유는 한국어가 영어와는 다른 형태를 가지는 언어인 교착어(조사, 어미 등을 붙여서 말을 만드는 언어)라는 점에서 기인한다.
교착어의 특성
영어와는 달리 한국어에서는 조사라는 것이 존재한다. 예를 들어 한국어에서 그(he/him)라는 주어나 목적어가 들어간 문장이 있다고 할 때, '그'라는 단어 하나에도 '그가', '그에게', '그를' 과 같이 다양한 조사가 '그'라는 글자 뒤에 띄어쓰기 없이 바로 붙게 된다. 자연어 처리를 하다보면 같은 단어임에도 서로 다른 조사가 붙어서 다른 단어로 인식이 되면 자연어 처리가 힘들고 번거로워지는 경우가 많다. 따라서 대부분의 한국어 NLP에서 조사는 분리해 줄 필요가 있다.
한국어 토큰화에서는 형태소(Morpheme)란 개념이 필요하다. 형태소란 뜻을 가진 가장 작은 말의 단위를 말한다. 이 형태소에는 자립 형태소와 의존 형태소가 있다.
자립 형태소 : 접사, 어미, 조사와 상관없이 자립하여 사용할 수 있는 형태소. 그 자체로 단어가 된다. 체언(명사, 대명사, 수사), 수식언(관형사, 부사), 감탄사 등이 있다.
의존 형태소 : 다른 형태소와 결합하여 사용되는 형태소. 접사, 어미, 조사, 어간을 말한다.
예를 들어 다음과 같은 문장이 있다고 하자.
에디가 책을 읽었다.
이 문장을 띄어쓰기 단위 토큰화를 수행한다면 다음과 같은 결과를 얻는다.
['에디가', '책을', '읽었다']
하지만 이를 형태소 단위로 분해하면 다음과 같다.
자립 형태소 : 에디, 책
의존 형태소 : -가, -을, 읽-, -었, -다
'에디'라는 사람 이름과 '책'이라는 명사를 얻을 수 있다. 이처럼 한국어에서 영어에서의 단어 토큰화와 유사한 형태를 얻으려면 어절 토큰화가 아니라 형태소 토큰화를 수행해야 한다.
한국어는 띄어쓰기가 영어보다 잘 지켜지지 않는다.
뉴스 기사와 같이 띄어쓰기를 철저하게 지키려고 노력하는 글이라면 좋겠지만, 많은 경우에 띄어쓰기가 틀렸거나 지켜지지 않는 코퍼스가 많다.
품사 태깅
단어는 표기는 같지만 품사에 따라서 단어의 의미가 달라지기도 한다. 예를 들어 '못'이라는 단어는 명사로서는 망치를 사용해 목재 따위를 고정하는 물건을 의미한다. 하지만 부사로서의 '못'은 '먹는다', '달린다'와 같은 동작 동사를 할 수 없다는 의미로 쓰인다. 결국 단어의 의미를 제대로 파악하기 위해서는 해당 단어가 어떤 품사로 쓰였는지 보는 것이 주요 지표가 될 수 있다. 그에 따라 단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지를 구분해놓기도 하는데, 이 작업을 품사태깅이라고 한다.
영어, 한국어 토큰화 예제
영어 토큰화 예제
NLTK에서는 Penn Treebank POS Tags라는 기준을 사용해 품사를 태깅한다.
단어 토큰화 : ['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are', 'a', 'Ph.D', 'student', '.']
품사 태깅 : [('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'), ('.', '.')]
영어 문장에 대해 토큰화를 수행한 결과이다.
Penn Treebank POG Tags에서
- PRP : 인칭 대명사
- VBP : 동사
- RB : 부사
- VBG : 현재부사
- IN : 전치사
- NNP : 고유 명사
- NNS : 복수형 명사
- CC : 접속사
- DP : 관사
를 의미한다.
한국어 토큰화 예제
한국어 자연어 처리를 위해서는 Konlpy라는 파이썬 패키지를 사용할 수 있다.
Konlpy를 통해 사용할 수 있는 형태소 분석기로는 Okt, Mecab, komoran, Hannanum, Kkma가 있다.
Konlpy에서 제공하는 각 형태소 분석기 별 처리 속도는 다음과 같다.
그래프만 놓고 보면 Mecab이 가장 빠르지만, 형태소 분석기의 성능은 처리 속도와 비례하지 않다.
따라서 Konlpy에서 제공하는 성능 분석표를 참고해 본인 상황에 맞는 형태소 분석기를 사용하는 것이 바람직하다.
Okt
Okt 형태소 분석 : ['열심히', '코딩', '한', '당신', ',', '연휴', '에는', '여행', '을', '가봐요']
Okt 품사 태깅 : [('열심히', 'Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('연휴', 'Noun'), ('에는', 'Josa'), ('여행', 'Noun'), ('을', 'Josa'), ('가봐요', 'Verb')]
Okt 명사 추출 : ['코딩', '당신', '연휴', '여행']
Kkma
Kkma 형태소 분석 : ['열심히', '코딩', '하', 'ㄴ', '당신', ',', '연휴', '에', '는', '여행', '을', '가보', '아요']
Kkma 품사 태깅 : [('열심히', 'MAG'), ('코딩', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('당신', 'NP'), (',', 'SP'), ('연휴', 'NNG'), ('에', 'JKM'), ('는', 'JX'), ('여행', 'NNG'), ('을', 'JKO'), ('가보', 'VV'), ('아요', 'EFN')]
Kkma 명사 추출 : ['코딩', '당신', '연휴', '여행']
앞선 Okt와 Kkma를 비교하면 같은 문장에 대해 다른 토큰화 결과가 나온다. 각 형태소 분석기는 성능과 결과가 다르게 나오기 때문에, 형태소 분석기의 선택은 사용하고자 하는 필요 용도에 어떤 형태소 분석기가 가장 적절한지 판단하고 사용해야 한다.
'NLP > 딥러닝을 이용한 자연어 처리 입문' 카테고리의 다른 글
[NLP] 1-4. 불용어(Stopword) (1) | 2023.11.30 |
---|---|
[NLP] 1-3. 추출(Stemming) (1) | 2023.11.29 |
[NLP] 1-2. 정제(Cleaning)와 정규화(Normalization) (0) | 2023.11.29 |
[NLP] 1. 전처리 과정 (0) | 2023.11.28 |
[NLP] 0. 자연어 처리란? (0) | 2023.11.28 |