자연어 처리(NLP)의 세계에서 '토큰화'는 텍스트 데이터를 컴퓨터가 이해할 수 있는 형태로 변환하기 위한 과정 중 하나로, 자연어를 잘게 쪼개어 분석 가능한 단위로 만드는 작업을 말합니다. 이 글에서는 토큰화의 정의와 유형, 그리고 사용 사례에 대해 자세히 살펴보겠습니다.
토큰화란 무엇인가?
토큰화(Tokenization)는 문장을 의미 있는 단위인 '토큰'으로 분리하는 과정을 의미합니다. 여기서 토큰은 단어, 어절, 혹은 심지어 문자일 수도 있습니다. 예를 들어, "오늘 날씨가 좋다"라는 문장은 토큰화 과정을 통해 ["오늘", "날씨가", "좋다"]와 같은 단어 단위로 나눌 수 있습니다. 컴퓨터는 이러한 토큰들을 통해 자연어 텍스트를 분석하고 이해할 수 있습니다.
토큰화의 유형
토큰화는 크게 두 가지 주요 유형으로 나뉩니다.
1. 단어 토큰화
텍스트를 단어 단위로 나누는 방법입니다. 이 경우 공백이나 구두점을 기준으로 텍스트를 분리합니다. 예를 들어, "나는 학교에 간다."라는 문장은 단어 단위로 ["나는", "학교에", "간다"]로 토큰화됩니다.
2. 문장 토큰화
텍스트를 문장 단위로 나누는 방법입니다. 이 경우 마침표, 느낌표, 물음표 등을 기준으로 문장을 구분합니다. 예를 들어, "오늘은 비가 온다. 그래서 우산을 가져왔다."라는 문장은 ["오늘은 비가 온다.", "그래서 우산을 가져왔다."]로 분리됩니다.
실습 코드 예제
다음은 Python의 NLTK 라이브러리를 사용하여 간단하게 토큰화를 수행하는 실습 코드 예제입니다.
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
# NLTK 데이터 다운로드 (최초 실행 시 필요)
nltk.download('punkt')
text = "오늘은 날씨가 좋고, 내일도 맑을 예정입니다. 나들이 가기 좋은 날씨네요."
# 문장 토큰화
sent_tokens = sent_tokenize(text)
print("문장 토큰화 결과:")
print(sent_tokens)
# 단어 토큰화
word_tokens = word_tokenize(text)
print("\n단어 토큰화 결과:")
print(word_tokens)
> 문장 토큰화 결과:
['오늘은 날씨가 좋고, 내일도 맑을 예정입니다.', '나들이 가기 좋은 날씨네요.']
> 단어 토큰화 결과:
['오늘은', '날씨가', '좋고', ',', '내일도', '맑을', '예정입니다', '.', '나들이', '가기', '좋은', '날씨네요', '.']
위 코드에서는 NLTK의 `sent_tokenize`와 `word_tokenize` 함수를 사용하여 문장과 단어 단위로 토큰화를 수행합니다. `punkt`는 NLTK에서 제공하는 토큰화를 위한 데이터로, 한국어와 영어 모두 지원합니다.
한글 토큰화
한국어 토큰화는 특히 어려운 작업 중 하나입니다. 한국어는 교착어로, 하나의 단어가 여러 형태소로 이루어져 있으며, 접사와 어미가 단어에 결합되어 문맥에 따라 다양한 의미를 가질 수 있습니다. 이러한 특성 때문에 한국어 토큰화에서는 형태소 분석이 중요합니다.
형태소 분석은 단어를 의미 있는 최소 단위인 형태소로 분리하고, 각각의 형태소가 어떤 품사인지 파악하는 과정을 포함합니다.
한국어 토큰화를 위해 자주 사용하는 도구로는 KoNLPy 라이브러리가 있습니다.
KoNLPy는 여러 형태소 분석기를 제공하며, 그중에서도 Okt, Kkma, Mecab 등이 많이 사용됩니다.
다음은 Okt 라이브러리를 사용하여 한국어 토큰화를 수행하는 예제입니다.
from konlpy.tag import Okt
# Okt 형태소 분석기 생성
okt = Okt()
# 예제 문장
text = "오늘은 날씨가 참 좋네요. 나들이 가기 좋은 날씨입니다."
# 형태소 단위로 토큰화
morphs = okt.morphs(text)
print("형태소 토큰화 결과:")
print(morphs)
# 명사 추출
nouns = okt.nouns(text)
print("\n명사 추출 결과:")
print(nouns)
# 품사 태깅
pos_tags = okt.pos(text)
print("\n품사 태깅 결과:")
print(pos_tags)
> 형태소 토큰화 결과:
['오늘', '은', '날씨', '가', '참', '좋네요', '.', '나들이', '가기', '좋은', '날씨', '입니다', '.']
> 명사 추출 결과:
['오늘', '날씨', '나들이', '가기', '날씨']
> 품사 태깅 결과:
[('오늘', 'Noun'), ('은', 'Josa'), ('날씨', 'Noun'), ('가', 'Josa'), ('참', 'Verb'), ('좋네요', 'Adjective'), ('.', 'Punctuation'), ('나들이', 'Noun'), ('가기', 'Noun'), ('좋은', 'Adjective'), ('날씨', 'Noun'), ('입니다', 'Adjective'), ('.', 'Punctuation')]
위 코드에서는 Okt 형태소 분석기를 사용하여 형태소 단위로 텍스트를 분리하고, 명사를 추출하며, 각 형태소에 대해 품사를 태깅합니다. 한국어는 문맥에 따라 형태가 달라지는 경우가 많기 때문에 이러한 형태소 분석 과정이 중요합니다.
다음은 Kkma 라이브러리를 사용하여 한국어 토큰화를 수행하는 예제입니다.
from konlpy.tag import Kkma
kkma = Kkma()
print('형태소 토큰화 결과 :',kkma.morphs(text))
print('명사 추출 결과:',kkma.nouns(text))
print('품사 태깅 결과 :',kkma.pos(text))
> 형태소 토큰화 결과 :
['오늘', '은', '날씨', '가', '참', '좋', '네요', '.', '나들이', '가기', '좋', '은', '날씨', '이', 'ㅂ니다', '.']
> 명사 추출 결과:
['오늘', '날씨', '나들이', '가기']
> 품사 태깅 결과 :
[('오늘', 'NNG'), ('은', 'JX'), ('날씨', 'NNG'), ('가', 'JKS'), ('참', 'MAG'), ('좋', 'VA'), ('네요', 'EFN'), ('.', 'SF'), ('나들이', 'NNG'), ('가기', 'NNG'), ('좋', 'VA'), ('은', 'ETD'), ('날씨', 'NNG'), ('이', 'VCP'), ('ㅂ니다', 'EFN'), ('.', 'SF')]
위 코드에서는 Kkma 형태소 분석기를 사용하여 형태소 단위로 텍스트를 분리하고, 명사를 추출하며, 각 형태소에 대해 품사를 태깅합니다.
Okt와 Kkma의 결과 비교
> Okt 형태소 토큰화 결과:
['오늘', '은', '날씨', '가', '참', '좋네요', '.', '나들이', '가기', '좋은', '날씨', '입니다', '.']
> Kkma 형태소 토큰화 결과 :
['오늘', '은', '날씨', '가', '참', '좋', '네요', '.', '나들이', '가기', '좋', '은', '날씨', '이', 'ㅂ니다', '.']
형태소 단위로 토큰화 비교
Okt는 "좋네요"를 하나의 단어로 인식하고, "좋은"과 같은 단어를 그대로 유지합니다.
Kkma는 "좋"과 "네요"를 두 개의 형태소로 분리하며, "좋은"도 "좋"과 "은"으로 나누어 처리합니다.
> Okt 품사 태깅 결과:
[('오늘', 'Noun'), ('은', 'Josa'), ('날씨', 'Noun'), ('가', 'Josa'), ('참', 'Verb'), ('좋네요', 'Adjective'), ('.', 'Punctuation'), ('나들이', 'Noun'), ('가기', 'Noun'), ('좋은', 'Adjective'), ('날씨', 'Noun'), ('입니다', 'Adjective'), ('.', 'Punctuation')]
> Kkma 품사 태깅 결과 :
[('오늘', 'NNG'), ('은', 'JX'), ('날씨', 'NNG'), ('가', 'JKS'), ('참', 'MAG'), ('좋', 'VA'), ('네요', 'EFN'), ('.', 'SF'), ('나들이', 'NNG'), ('가기', 'NNG'), ('좋', 'VA'), ('은', 'ETD'), ('날씨', 'NNG'), ('이', 'VCP'), ('ㅂ니다', 'EFN'), ('.', 'SF')]
품사 태깅 비교
Okt는 품사를 "Noun", "Verb", Adjective"등으로 태깅하지만,
Kkma는 "NNG", "JX", "JKS", "MAG" 등으로 더욱 세분화된 품사 태그를 사용합니다.
한국어는 왜 어려울까?
한국어 토큰화에서의 어려움은 몇 가지 이유로 인해 영어와는 다릅니다. 영어는 대개 띄어쓰기를 기준으로 단어를 구분할 수 있지만, 한국어는 그렇지 않기 때문에 더 복잡한 처리가 필요합니다. 다음은 한국어 토큰화에서 겪는 몇 가지 주요 어려움을 설명한 내용입니다.
1. 한국어의 교착어 특성
영어에서는 단어가 독립적으로 존재하는 경우가 많지만, 한국어는 교착어입니다. 교착어란 주어, 목적어 등에 조사나 어미를 붙여서 문장을 구성하는 언어를 말합니다.
예를 들어, '그'라는 단어는 '그가', '그를', '그에게' 등으로 다양한 조사가 붙습니다. 이런 조사는 띄어쓰기가 없는 상태로 결합되므로, 단순히 띄어쓰기를 기준으로 단어를 나누는 것만으로는 올바른 단어 단위 토큰화를 수행할 수 없습니다.
* 어절은 띄어쓰기로 구분된 단위를 말합니다.
* 형태소는 의미를 가지는 최소의 단위입니다.
이를 해결하기 위해서는 형태소 단위로 텍스트를 나눠야 합니다.
형태소(morpheme)란 의미를 가지는 가장 작은 단위로, 크게 두 가지로 구분됩니다.
- 자립 형태소: 명사, 동사 등처럼 홀로 사용할 수 있는 형태소.
- 의존 형태소: 조사나 어미처럼 다른 단어와 결합해야 의미를 가지는 형태소.
예를 들어 "에디가 책을 읽었다"라는 문장을 형태소 단위로 나누면, '에디'와 '책'은 자립 형태소이고, '가', '을', '읽', '었다'는 의존 형태소입니다. 이러한 과정은 자연어 처리에서 중요하며, 한국어에서는 형태소 토큰화가 단어 단위 토큰화보다 더 적합합니다.
2. 띄어쓰기의 불규칙성
한국어는 영어와 비교했을 때 띄어쓰기가 엄격하게 지켜지지 않는 경우가 많습니다. 뉴스 기사처럼 띄어쓰기가 비교적 잘 지켜진 텍스트라면 처리하기 쉽지만, 일반적인 텍스트에서는 띄어쓰기가 틀리거나 아예 없는 경우가 빈번합니다. 예를 들어, "제가이렇게말씀드리는것처럼" 같은 텍스트에서도 대부분의 한국어 화자는 내용을 이해할 수 있지만, 영어에서는 "Thisisnotproperspacing"과 같은 문장은 이해하기 어렵습니다. 이런 특성 때문에 한국어 토큰화는 띄어쓰기를 기준으로 처리하는 것이 더욱 복잡해집니다.
3. 품사 태깅의 필요성 (Part-of-Speech tagging)
단어가 어떤 품사로 사용되었는지에 따라 그 의미가 달라질 수 있기 때문에, 품사 태깅은 단어의 의미를 정확히 파악하는 데 중요한 역할을 합니다. 예를 들어, '못'이라는 단어는 망치를 사용하는 '못'일 수도 있고, '하지 못한다'의 부정 표현일 수도 있습니다. 이처럼 단어의 의미를 정확히 구분하기 위해 품사를 구분하는 작업이 필요하며, 이를 "품사 태깅"이라고 합니다.
영어의 경우에는 `nltk`를, 한국어의 경우에는 `KoNLPy` 라이브러리를 사용하여 품사 태깅을 할 수 있습니다.
(한국어 예시 코드는 위에 있음)
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
# 텍스트 문장
text = "I am actively looking for Ph.D. students. Are you a Ph.D. student?"
# 단어 토큰화
tokenized_sentence = word_tokenize(text)
# 품사 태깅
tagged_sentence = pos_tag(tokenized_sentence)
print("단어 토큰화 :", tokenized_sentence)
print("품사 태깅 :", tagged_sentence)
> 단어 토큰화 :
['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'Are', 'you', 'a', 'Ph.D.', 'student', '?']
> 품사 태깅 :
[('I', 'PRP'), ('am', 'VBP'), ('actively', 'RB'), ('looking', 'VBG'), ('for', 'IN'), ('Ph.D.', 'NNP'), ('students', 'NNS'), ('.', '.'), ('Are', 'VBP'), ('you', 'PRP'), ('a', 'DT'), ('Ph.D.', 'NNP'), ('student', 'NN'), ('?', '.')]
4. 형태소 분석기 선택의 중요성
한국어 자연어 처리를 위한 형태소 분석기가 다양하게 존재하는데요. 대표적인 분석기로는 Okt, Kkma, Hannanum, Komoran, Mecab 등이 있으며, 각 분석기마다 성능과 속도가 다릅니다. 예를 들어, 속도가 중요한 경우에는 Mecab을 사용할 수 있으며, 정밀한 분석이 필요할 때는 Kkma나 Okt를 선택할 수 있습니다. 각 분석기는 텍스트의 성격에 따라 적절한 분석기를 선택하는 것이 중요합니다.
이처럼 한국어 토큰화는 언어적 특성과 불규칙성 때문에 영어보다 복잡한 처리가 필요하며, 자연어 처리에서는 형태소 단위로 나누는 것이 적합한 경우가 많습니다.
토큰화를 할 때 주의해야 할 점
토큰화를 할 때 주의해야 할 점은 텍스트 데이터의 특성, 분석 목적, 그리고 사용할 모델에 따라 달라질 수 있습니다. 아래는 토큰화를 할 때 주의해야 할 몇 가지 중요한 사항들입니다.
1. 언어 특성에 따른 차이
영어는 주로 공백을 기준으로 단어 토큰화를 할 수 있지만, 한글은 조사를 포함하고 있어서 공백만으로는 정확한 토큰화가 어렵습니다. 한글 텍스트에서는 형태소 분석을 통해 토큰화하는 것이 일반적입니다.
2. 구두점 처리
구두점(예: 마침표, 쉼표 등)을 포함할지, 제외할지 결정해야 합니다. 분석 목적에 따라 구두점을 보존해야 할 수도 있고, 구두점이 의미가 없을 경우 제거하는 것이 좋을 수도 있습니다. 예를 들어, 감정 분석에서는 구두점이 감정의 강도를 표현할 수 있기 때문에 중요할 수 있습니다.
3. 줄임말과 특수 기호 처리
영어에서 "I'm", "don't" 같은 줄임말은 "I"와 "am", "do"와 "not"으로 나눌지, 아니면 하나의 토큰으로 처리할지에 대한 기준이 필요합니다.
특수 기호(예: 이메일 주소, 해시태그, URL 등)를 어떻게 처리할지도 고려해야 합니다. 일부 분석에서는 중요한 정보가 될 수 있고, 다른 경우에는 불필요한 데이터로 취급될 수 있습니다.
4. 어간 추출(Stem) 및 원형 복원(Lemmatization)
- 어간 추출(Stemming): 단어의 어미를 제거하여 기본 형태로 변환하는 과정입니다. 예를 들어 "studies"를 "studi"로 변환합니다. 이 방법은 간단하지만, 언어적 의미를 손상시킬 수 있습니다.
- 원형 복원(Lemmatization): 단어의 원형을 복원하는 작업으로, "studies"는 "study"로 변환됩니다. 어간 추출보다 의미를 보존하는 장점이 있습니다.
- 분석 목적에 따라 어간 추출 또는 원형 복원을 적용할지 결정해야 합니다.
5. Stop Words 처리
"the", "and", "is" 같은 자주 등장하는 불용어(stop words)는 많은 경우 의미를 담고 있지 않으므로 제거됩니다. 하지만 불용어를 제거하면 중요한 정보를 잃을 수 있는 경우도 있습니다. 따라서, 불용어 처리 여부를 신중하게 결정해야 합니다. 한글에서는 "이", "그", "저" 같은 조사와 불용어가 처리 대상입니다.
6. 단어 조합(N-grams) 고려
텍스트 데이터를 단어 하나씩 처리하면 충분하지 않을 때, 연속된 단어들을 하나의 토큰으로 처리하는 방법이 있습니다. 예를 들어, "New York"은 두 개의 단어지만, 하나의 개념으로 인식해야 할 때가 있습니다. N-grams(예: 2-gram, 3-gram)는 여러 단어를 조합해 문맥을 더 잘 반영할 수 있도록 합니다.
7. 희귀 단어 처리
너무 자주 등장하거나 너무 적게 등장하는 단어는 모델 학습에 방해가 될 수 있습니다. 예를 들어, 아주 희귀한 단어는 분석 결과에서 제거하거나 하위 단어 단위로 나누는 방식(Subword 토큰화)으로 처리할 수 있습니다.
8. 토큰 길이 제한
NLP 모델에서는 입력 데이터의 길이를 제한하는 경우가 많습니다(예: BERT 모델은 최대 512개의 토큰을 처리). 입력 텍스트가 너무 길 경우에는 토큰 수를 조절하거나 자르는 방법이 필요합니다.
9. 대소문자 처리
영어에서는 대소문자를 통일할지 여부를 결정해야 합니다. 보통은 모두 소문자로 변환하여 처리하지만, 특정 분석에서는 대문자가 의미를 가질 수 있기 때문에 그대로 유지할 수도 있습니다. 예를 들어, "Apple"은 회사 이름일 수도 있고, "apple"은 과일일 수도 있습니다.
10. 언어 모델의 특성 고려
BPE(Byte Pair Encoding)나 WordPiece 같은 하위 단어 토큰화는 Transformer 계열 모델(예: BERT, GPT)에서 자주 사용됩니다. 이 방식들은 희귀 단어 처리에 유용하며, 토큰화된 결과를 모델에 맞게 처리하는 것이 중요합니다. 분석할 텍스트의 특성에 따라 적절한 토크나이저를 선택하는 것이 중요하겠죠. 예를 들어, 형태소 기반 토큰화는 한글에 적합하고, 하위 단어 기반 토큰화는 BERT와 같은 언어 모델에 적합합니다.
토큰화의 사용 사례
토큰화는 다양한 자연어 처리 작업에서 중요한 역할을 합니다.
예를 들어, 감정 분석(Sentiment Analysis)에서는 텍스트를 단어 단위로 나누어 긍정적, 부정적 감정을 판단하는 데 사용됩니다. 챗봇 개발에서도 사용자가 입력한 문장을 토큰화하여 의미를 파악하고 적절한 응답을 생성합니다.
또한, 기계 번역에서도 소스 언어의 문장을 토큰으로 나누어 번역 과정을 수행합니다.