토큰화(Tokenization)

ganta·2021년 3월 2일
0

자연어 전처리

목록 보기
2/8
post-thumbnail

이 글은 Wikidocks의 딥 러닝을 이용한 자연어 치리 입문을 공부한 내용을 정리 한 글입니다.

토큰화(Tokenization)


✔️ 토큰화란?
주어진 코퍼스(corpus)에서 토큰(token)이라 불리는 단위로 나누는 작업이다.

단어 토큰화(Word Tokenization)


✔️ 단어 토큰화(Word Tokenization)란?
토큰의 기준을 단어로 하는 경우 단어 토큰화(Word Tokenization)라 한다.
이때, 단어(word)는 단어 단위 외 단어구, 의미를 갖는 문자열로도 간주된다.

✔️ 예시
👉 input : This is simple example!
이때, 입력으로부터 구두점(punctuation)과 같은 문자는 제외시켜 단어 토큰화를 시켜보면 다음과 같다.
(구두점이란, 마침표(.), 컴마(,), 물음표(?), 세미콜론(;), 느낌표(!)같은 기호를 말함)
👉 output : "This", "is", "simple", "example"
❗️보통 토큰화 작업은 단순히 구두점이나 특수문자를 전부 제거하는 정제(cleaning)작업을 수행하는 것만으로는 해결되지 않는다.(구두점을 지우면 토큰이 의미를 잃어버리는 경우도 생김) - 특히 한국어는 띄어쓰디만으로는 단어 토큰을 구분하기 어러운 경우가 많음

토큰화 수행 중 선택의 순간

✔️ 토큰화시 예상치 못한 경우가 있어 토큰화의 기준을 생각해 봐야 한다.

✔️ 예시
👉 input : Don't forget my name
이때, 아포스트로피를(')가 들어가있는 단어의 토큰 과정을 고려해보면 다음과 같다.
Don't
Don t
Dont
Do n't
라이브러리 사용 시 결과가 사용자의 목적과 일치한지 고려를 해야 한다.
만약 목적과 맞다면 사용하고 맞지 않으면 원하는 결과가 나오도록 토큰화 도구를 직접 설계도 가능하다.
👉 output

from nltk.tokenize import word_tokenize  
print(word_tokenize("Don't forget my name"))
['Do', "n't", 'forget', 'my', 'name']
from nltk.tokenize import WordPunctTokenizer  
print(WordPunctTokenizer().tokenize("Don't forget my name"))
['Don', "'", 't', 'forget', 'my', 'name']
from tensorflow.keras.preprocessing.text import text_to_word_sequence
print(text_to_word_sequence("Don't forget my name"))
["don't", 'forget', 'my', 'name']

도구에 따른 다른 토큰들을 얻는 것을 볼 수 있다.

토큰화 시 고려 사항

✔️ 구두점이나 특수 문자를 단순 제외해서는 안 된다.
구두점 또한 의미를 담고 있는 경우가 있어 이를 토큰에 포함시키는 경우가 있다.
예를 들어 '.'의 경우 문장의 경계 혹은 ph.D같은 단어 자체에서도 가질 수 있다.(하나의 의미) 또한, 숫자의 ','또한 예시에 해당 될 수 있다.

✔️ 줄임말과 단어 내에 띄어쓰기가 있는 경우
👉 줄임말 예시
we're -> we are
I'm -> i am
👉 띄어쓰기 예시
New York, rock 'n' roll

✔️ 표준 토큰화 예제
Penn Treebank Tokenization의 규칙은 다음과 같다.
1️⃣ 하이푼으로 구성된 단어는 하나로 묶음
2️⃣ 아포스트로피(')로 '접어'가 함께하는 단어는 분리해준다.

from nltk.tokenize import TreebankWordTokenizer
tokenizer=TreebankWordTokenizer()
print(tokenizer.tokenize("we're family"))
['we', "'re", 'family']
from nltk.tokenize import TreebankWordTokenizer
tokenizer=TreebankWordTokenizer()
print(tokenizer.tokenize("I will stay this place long-term period"))
['I', 'will', 'stay', 'this', 'place', 'long-term', 'period']

문장 토큰화(Sentence Tokenization)


✔️ 문장 토큰화(Sentence Tokenization)는 코퍼스 내에 문장 단위로 구분할 때 주로 사용을 하는 토큰화 방법이다.

✔️ 단순하게 '?'나 마침표, '!'등의 기호로 분리하면 되지 않을까 생각되나 꼭 그렇지만은 않다.
'!'나 '?'는 문장의 구분을 위한 꽤 명확한 구분자(boundary) 역할을 하지만 마침표는 꼭 그렇지 않기 때문(예를 들어 ip주소나 이메일 주소 같은 경우)

✔️ 이로 인해 삿 언어에 따라 직접 규칙들을 정의하여 토큰화를 수행하지만 코퍼스 데이터에 오타나, 문장의 구성이 엉망이면 정해놓은 규칙이 소용이 없을 수 있다.

✔️ 예시

from nltk.tokenize import sent_tokenize
print(sent_tokenize("I like you. you're my son"))
['I like you.', "you're my son"]

한국어 같은 경우 KSS같은 라이브러리들이 존재한다.

from kss import split_sentences
text = "차근차근 해보죠. 언젠간 이룰 수 있을 거에요"
split_sentences(text)
['차근차근 해보죠.', '언젠간 이룰 수 있을 거에요']

이진 분류기(Binary Classifier)

✔️ 문장 토큰화에서의 예외 사항을 발생시키는 마침표 처리를 위해 두개의 클래스로 분류하는 이진 분류기(binary classifier)를 사용한다.
1️⃣ 마침표가 약어(abbreivation)로 쓰이는 경우
2️⃣ 문장의 구분자(boundary)일 경우

✔️ 이를 구현하는 방법은 여러 규칙을 코딩한 함수가 될 수도 있고, 머신 러닝을 통해 이진 분류기를 사용하기도 한다.

✔️ 약어들은 미리 정의된 약어 사전을 사용하는 경우도 많다.

한국어에서의 토큰화의 어려움


✔️ 한국어의 경우 띄어쓰기 단위가 되는 단위를 어절이라 하는데 저덜 토큰화는 한국어 NLP에서 지양되고 있다. => 어절 토큰화가 단어 토큰화가 같지 않기 때문

✔️ 한국어는 교착어
같은 단어임에도 조사에 따라 의미가 바뀌어 자연어 처리가 어려운 경우가 있어 한국어 NLP에서 조사는 분리 할 필요가 있다.
⭐️ 한국어에서는 형태소(뜻을 가진 가장 작은 말의 단위) 단위로 토큰화가 이뤄진다.
형태소의 종류
1️⃣ 자립 형태소 : 접사, 어미, 조사와 상관없이 자립하여 사용할 수 있는 형태소로써 체언, 수식언, 감탄사 등이 해당
2️⃣ 의존 형태소 : 다른 형태소와 결합하여 사용되는 형태소로써 접사, 어미, 조사, 어간을 말함


✔️ 한국어는 띄어쓰기가 영어보다 잘 지켜지지 않는다.
한국어는 띄어쓰기가 잘 지켜지지 않아도 의미 파악이 영어보다 수월하다.

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


✔️ 품사에 따라 의미가 달라지는 경우가 있기 때문에 품사를 구별해 주는 작업은 굉장히 중요하다.
fly - 명사 : 파리/ 동사 : 날다.

코드 실습


from nltk.tokenize import word_tokenize
text="I like you because you're my son."
print(word_tokenize(text))
['I', 'like', 'you', 'because', 'you', "'re", 'my', 'son', '.']
from nltk.tag import pos_tag
x=word_tokenize(text)
pos_tag(x)
[('I', 'PRP'),
 ('like', 'VBP'),
 ('you', 'PRP'),
 ('because', 'IN'),
 ('you', 'PRP'),
 ("'re", 'VBP'),
 ('my', 'PRP$'),
 ('son', 'NN'),
 ('.', '.')]
# 형태소마다 분리
from konlpy.tag import Okt  
okt=Okt()  
print(okt.morphs("열심히 일한 당신, 떠나라!"))
['열심히', '일', '한', '당신', '!', '떠나라', '!']
print(okt.pos("열심히 일한 당신, 떠나라!"))  
[('열심히', 'Adverb'), ('일', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), ('!', 'Punctuation'), ('떠나라', 'Verb'), ('!', 'Punctuation')]
print(okt.nouns("열심히 일한 당신, 떠나라!"))  
['일', '당신']
from konlpy.tag import Kkma  
kkma=Kkma()  
print(kkma.morphs("열심히 일한 당신, 수고한 만큼 떠나라!"))
['열심히', '일한', '당', '신', '!', '수고', '하', 'ㄴ', '만큼', '떠나', '라', '!']
print(kkma.pos("열심히 일한 당신, 수고한 만큼 떠나라!")) 
[('열심히', 'MAG'), ('일한', 'NNG'), ('당신', 'NP'), (',', 'SP'), ('수고', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('만큼', 'NNB'), ('떠나', 'VV'), ('라', 'EFN'), ('!', 'SF')]
print(kkma.nouns("열심히 일한 당신, 수고한 만큼 떠나라!")) 
['일한', '당신', '수고', '만큼']
profile
한걸음씩 꾸준히

0개의 댓글