자연어 처리에서 데이터를 전처리하기 위해서 토큰화 - 정제 - 정규화 과정을 거친다.
토큰화
토큰화: corpus에서 토큰이라 불리는 단위로 나누는 작업
코퍼스(corpus): 특정한 목적을 가지고 특정 집단 내에서 사용하는 언어의 표본을 추출한 집합
단어 토큰화
토큰의 기준을 단어(단어구, 의미를 갖는 문자열)로 하는 경우다.
가장 기본적인 토큰화
ex) 구두점을 제외하고 띄어쓰기를 기준으로 자르기
그러나 구두점이나 특수문자를 제거하면 토큰이 의미를 잃어버리는 경우가 발생하기도 한다.
토큰화 기준과 함수
토큰화의 기준을 생각해봐야 하는 경우 -> 용도에 따라 영향이 없는 기준으로 선택한다.
Don't와 Jane's의 경우 '에 대해서 어떻게 처리할 것인지에 대한 기준이 필요하다.
토큰화 도구를 직접 설계할 수도 있지만 NLTK에서 제공하는 토큰화 도구를 사용할 수도 있다.
토큰화 도구를 사용하기 위해서는 아래와 같이 nltk 라이브러리르 설치해야한다.
pip install nltk
그리고 차후 코드 실행 시 아래 사진과 같은 오류가 발생한다면 오류 설명에 있는대로 실행하면 된다.
import nltk
nltk.download('punkt')
설치한 라이브러리를 import 하고 함수들을 사용한 결과는 다음과 같다.
토큰화를 할 텍스트는 아래에 있는 문장을 사용할 것이다.
from nltk.tokenize import word_tokenize
from nltk.tokenize import WordPunctTokenizer
from tensorflow.keras.preprocessing.text import text_to_word_sequence
text = "I don't like Jane's hair-line. I like Amy's skin."
word_tokenize()
tokenize1 = word_tokenize(text)
print(tokenize1)
# ['I', 'do', "n't", 'like', 'Jane', "'s", 'hair-line', '.', 'I', 'like', 'Amy', "'s", 'skin', '.']
don't를 do와 n't로 분리하고, Jane's를 Jane과 's로 분리했다.
WordPunctTokenizer().tokenize()
tokenize2 = WordPunctTokenizer().tokenize(text)
print(tokenize2)
# ['I', 'don', "'", 't', 'like', 'Jane', "'", 's', 'hair', '-', 'line', '.', 'I', 'like', 'Amy', "'", 's', 'skin', '.']
don't와 Jane's모두 구두점(')을 별도로 분리했다.
text_to_word_sequence()
tokenize3 = text_to_word_sequence(text)
print(tokenize3)
# ['i', "don't", 'like', "jane's", 'hair', 'line', 'i', 'like', "amy's", 'skin']
'를 구두점으로 보지않고 띄어쓰기만으로 분리했다.
추가적으로 모든 문자를 소문자로 변경했다.
토큰화 고려 사항
1. 구두점 및 특수문자 단순 제외 금지
- 문장의 끝을 나타내는 마침표(.)
- Ph.D 와 같은 줄임말에 사용되는 마침표(.)
- $12 처럼 가격을 나타내는 기호
- 12.34 처럼 소수점을 나타내는 마침표(.)
- 02/02/02 02:02:02 처럼 날짜와 시간을 나타내는 기호
- 숫자 사이에 표시되는 콤마(,)
2. 줄임말과 단어 내에 띄어쓰기
- I'm -> I am 과 같이 '로 단어를 압축
- New York 과 같은 하나의 단어 사이 내의 띄어쓰기
3. 표준 예제
- 하이픈으로 구성된 단어는 하나로 유지
- don't와 같이 '로 접어가 함께하는 단어는 분리
이 규칙을 따르는 함수로 트리뱅크 워드토크나이저가 있다.
from nltk.tokenize import TreebankWordTokenizer
tokenizer = TreebankWordTokenizer()
tokenize = tokenizer.tokenize(text)
print(tokenize)
# ['I', 'do', "n't", 'like', 'Jane', "'s", 'hair-line.', 'I', 'like', 'Amy', "'s", 'skin', '.']
위의 word_tokenize()와 비슷한 것 같지만 맨 마지막 문장을 제외하고 마침표를 별도로 분리하지 않는다.
문장 토큰화
토큰의 단위가 문장인 경우를 말한다.
직관적으로 . ? ! 를 기준으로 문장을 잘라낼 수 있지만 '내 IP 주소는 192.168.0.0 이야.' 라는 문장에서
문장 끝 이전에 나오는 마침표로 분리될 수 있다.
sent_tokenize()
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.']
'''
함수를 이용하여 단순히 마침표를 구분자로 인지하지 않고 단어로 인식하는 것을 확인할 수 있다.
kss.split_sentences()
kss 를 이용해 한국어도 문장 토큰화를 할 수 있다.
import kss
text = '나는 S.Y. 슈퍼에 갔어요. 오늘의 할인율은 아마도 23.2%일걸요?'
print(kss.split_sentences(text))
'''
['나는 S.Y. 슈퍼에 갔어요.',
'오늘의 할인율은 아마도 23.2%일걸요?']
'''
굉장히 잘 되는 것을 확인할 수 있다.
한국어 토큰화의 어려움
한국어는 영어와 달리 띄어쓰기만으로 토큰화를 하기에는 어려움이 있다.
한국어는 띄어쓰기를 기준으로 '어절'이라고 하는데 어절 토큰화(!= 단어 토큰화)는 지양된다.
한국어는 교착어(조사, 어미 등 붙여서 말을 만드는 언어)이기 때문이다
한국어는 어절이 독립적인 단어로 구성되지 않기에 조사를 분리하여야 한다.
한국어 토큰화를 위해서는 가장 작은 말의 단위인 형태소를 알아야 한다.
- 자립 형태소: 조사, 어미와 상관없이 자립하여 사용할 수 있는 형태소
- 의존 형태소: 접사, 어미 등 다른 형태소와 결합하여 사용되는 형태소
ex) 에다가 책을 읽었다
- 자립 형태소: 에디, 책
- 의존 형태소: -가, -을, 읽-, -었, -다
또한, 한국어는 띄어스기가 잘 지켜지지 않는다.
품사 태깅
단어는 품사에 따라 의미가 달라지기도 한다.
'못'의 경우 명사로서는 망치를 사용해 목재 따위를 고정하는 물건이지만 부사로서는 동사를 할 수 없다는 의미다.
따라서 단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지 구분하기도 한다.
pos_tag()
영어 문장을 태깅하기 위해서는 pos_tag() 함수를 사용한다.
from nltk.tag import pos_tag
tag = pos_tag(word_tokenize(text))
print(tag)
# [('I', 'PRP'), ('do', 'VBP'), ("n't", 'RB'), ('like', 'VB'), ('Jane', 'NNP'), ("'s", 'POS'), ('hair-line', 'NN'), ('.', '.'), ('I', 'PRP'), ('like', 'VBP'), ('Amy', 'NNP'), ("'s", 'POS'), ('skin', 'NN'), ('.', '.')]
KoNLPy
한국어는 KoNLPy 패키지를 사용한다.
Okt, Kkma 등이 있다.
# Okt
from konlpy.tag import Okt
okt = Okt()
kText = "나는 사과가 좋아. 너는 귤이 싫어?"
print('OKT 형태소 분석 :',okt.morphs(kText))
print('OKT 품사 태깅 :',okt.pos(kText))
print('OKT 명사 추출 :',okt.nouns(kText))
'''
OKT 형태소 분석 : ['나', '는', '사과', '가', '좋아', '.', '너', '는', '귤', '이', '싫어', '?']
OKT 품사 태깅 : [('나', 'Noun'), ('는', 'Josa'), ('사과', 'Noun'), ('가', 'Josa'), ('좋아', 'Adjective'), ('.', 'Punctuation'), ('너', 'Noun'), ('는', 'Josa'), ('귤', 'Noun'), ('이', 'Josa'), ('싫어', 'Adjective'), ('?', 'Punctuation')]
OKT 명사 추출 : ['나', '사과', '너', '귤']
'''
morphs는 형태소 단위로 토큰화를 한다.
pos는 품사 태깅을 한다.
nouns는 명사만을 추출한다.
# Kkoma
from konlpy.tag import Kkma
kkma = Kkma()
print('꼬꼬마 형태소 분석 :',kkma.morphs(kText))
print('꼬꼬마 품사 태깅 :',kkma.pos(kText))
print('꼬꼬마 명사 추출 :',kkma.nouns(kText))
'''
꼬꼬마 형태소 분석 : ['나', '는', '사과', '가', '좋', '아', '.', '느', '어', '는', '귤', '이', '싫', '어', '?']
꼬꼬마 품사 태깅 : [('나', 'VV'), ('는', 'ETD'), ('사과', 'NNG'), ('가', 'JKS'), ('좋', 'VA'), ('아', 'ECD'), ('.', 'SF'), ('느', 'VV'), ('어', 'ECS'), ('는', 'JX'), ('귤', 'NNG'), ('이', 'JKS'), ('싫', 'VA'), ('어', 'ECD'), ('?', 'SF')]
꼬꼬마 명사 추출 : ['사과', '귤']
'''
함수들은 같은 동작을 하지만 결과가 다른 것을 볼 수 있다.
Kkoma가 Okt 에 비해 더 세분화하여 토큰화 하는 것을 확인할 수 있다.
정제
토큰화 작업 전과 후 텍스트 데이터를 용도에 맞게 정제와 정규화 작업이 진행된다.
정제란 코퍼스로부터 노이즈 데이터를 제거하는 것이다.
정제 작업은 토큰화 작업에 방해 되는 부분을 배제 시키기 위해 사전에 작업되기도 하지만,
토큰화 이후에 남아있는 노이즈를 제거하기 위해 사후에도 지속적으로 이루어진다.
대소문자 통합
대소문자를 통합함으로서 단어의 개수를 줄일 수 있다.
영어는 대부분 문장의 첫 글자만 대문자로 쓰기 때문에 대문자를 소문자로 변환하는 것이 유리하다.
그러나 US와 us 처럼 대소문자로서 의미를 나타내는 단어도 있기 때문에 무조건 변환해서는 안된다.
대소문자를 변경하는 다른 방안으로는 일부만 소문자로 변환시키는 방법도 있다.
문장의 맨 앞에 나오는 대문자만 소문자로 바꾸고 다른 단어들은 전부 대문자인 상태로 두는 것이다.
그러나 이런 방법 또한 대소문자를 크게 신경 쓰지 않고 글을 작성한 경우 의미가 없어진다.
따라서 글의 형태에 따라 맞는 방안을 고려해야 한다.
불필요한 단어 제거
정제 작업에서의 노이즈는 자연어도 아니고 의미도 없는 단어를 의미하기도 하지만 분석 목적에 맞지 않는 단어도 노이즈라고 한다. 예시로는 불용어, 등장 빈도가 적은 단어, 길이가 짧은 단어 등이 있다.
등장 빈도가 적은 단어
스팸 메일을 분류하는 경우 스팸 메일 100000개 중에서 5번 밖에 등장하지 않은 단어를 의미한다.
이 단어는 스팸 메일을 분류할 때 거의 도움이 되지 않을 것이다.
길이가 짧은 단어
한국어와 달리 영어에서는 길이가 짧은 단어를 삭제하는 것만으로도 효과를 볼 수 있다고 한다.
이 때 구두점들까지도 한 번에 제거할 수 있다고 한다.
그러나 한국어에서는 짧은 단어를 제거하는 것이 크게 유효하지는 않다.
영단어의 평균 길이는 6~7 이지만 한국어 단어의 평균 길이는 2~3 정도이다.
이런 특성으로 인해 영어에서는 관사 a 나 I와 같이 큰 의미가 없거나 in, on 과 같은 전치사를 제거할 수 있다.
쉬운 단어들인 fox, car 등은 3글자 이기 때문에 3글자 부터는 좀 더 유의해서 사용해야 한다.
정규화
정규화는 표현 방법이 다른 단어들을 통합시켜 같은 단어로 만드는 것이다.
정규 표현식
코퍼스에서 노이즈 데이터의 특징을 찾을 수 있다면, 정규 표현식을 통해 이를 제거할 수 있다.
정규 표현식을 이용하면 코퍼스 내에 계속해서 등장하는 글자들을 규칙에 기반하여 한 번에 제거할 수 있다.
정규 표현식 문법은 너무 많기 때문에 링크를 남긴다.
'AI > NLP' 카테고리의 다른 글
[Wiki] 원-핫 인코딩 (0) | 2024.06.02 |
---|---|
[Wiki] 패딩 (0) | 2024.06.01 |
[Wiki] 정수 인코딩 (0) | 2024.06.01 |
[Wiki] 불용어 (0) | 2024.06.01 |
[Wiki] 어간 추출 (0) | 2024.06.01 |