Artificial Intelligence/[파이썬 머신러닝 완벽가이드]

[파이썬 머신러닝 완벽가이드] Chap08-2. 텍스트 사전 준비 작업(텍스트 전처리) - 텍스트 정규화

aiclaudev 2022. 1. 12. 18:30

 

 

 

- 본 글은 파이썬 머신러닝 완벽 가이드 (권철민 지음)을 공부하며 내용을 추가한 정리글입니다. 개인 공부를 위해 만들었으며, 만약 문제가 발생할 시 글을 비공개로 전환함을 알립니다.

 

 

 

텍스트 정규화 작업은 크게 다음과 같이 분류할 수 있습니다.

ㆍ클렌징(Cleansing)

ㆍ토큰화(Tokenization)

ㆍ필터링 / 스톱 워드 제거 / 철자 수정

ㆍStemming

ㆍLemmatization

 

 

 

[1] 텍스트 토큰화

토큰화는 문장 토큰화와 단어 토큰화로 나눌 수 있습니다.

토큰화란 '더 작은 단위로 나누는 것' 정도로 이해하면 되는데요, 문장 토큰화란 전체 텍스트 문서에서 문장 단위로 나누는 것, 단어 토큰화란 문장에서 단어 단위로 나누는 것이라고 생각하면 됩니다.

 

① 문장 토큰화

문장 토큰화는 문장의 마침표(.), 개행문자(\n) 등 문장의 마지막을 뜻하는 기호에 따라 분리하는 것이 일반적입니다. NLTK에서 일반적으로 많이 쓰이는 sent_tokenize를 이용해 토큰화를 수행해봅시다.

 

from nltk import sent_tokenize
import nltk
nltk.download('punkt') # 마침표, 개행문자 등의 데이터 세트

text_sample = "The Matrix is everywhere its all around us, here even in this room. \
You can see it out your window or on your television. \
You feel it when you go to work, or go to church or pay your taxes."

sentences = sent_tokenize(text_sample)
print(type(sentences), len(sentences))
print(sentences)

리스트 형태로 반환해주는 것을 알 수 있네요. 리스트의 각 원소는 각 문장입니다.

 

 

② 단어 토큰화

단어 토큰화는 공백, 콤마(,), 마침표(.), 개행문자 등으로 단어를 분리합니다. word_tokenize를 이용해보죠.

 

from nltk import word_tokenize

sentence = "The Matrix is everywhere its all around us, here even in this room."
words = word_tokenize(sentence)
print(type(words), len(words))
print(words)

이 역시 리스트가 반환되네요. 각 원소는 한 문장 내에서의 단어입니다.

 

 

이제는 sent_tokenize와 word_tokenize를 모두 이용하여, 하나의 텍스트를 단어로 토큰화해봅시다.

from nltk import word_tokenize, sent_tokenize

# 여러 개의 문장으로 된 입력 데이터를 문장별로 단어 토큰화하게 만드는 함수 생성
def tokenize_text(text) :
    #문장별로 분리 토큰
    sentences = sent_tokenize(text)
    word_tokens = [word_tokenize(sentence) for sentence in sentences] # 이중 리스트
    return word_tokens

# 여러 문장에 대해 문장별 단어 토큰화 수행
word_tokens = tokenize_text(text_sample)
print(type(word_tokens), len(word_tokens))
print(word_tokens)

전체 텍스트에서 문장을 토큰화하고, 각 문장을 단어로 토큰화한 것을 볼 수 있네요. 위 코드에서는 한줄 for문을 사용하였습니다.

 

문장을 단어별로 하나씩 토큰화 할 경우 문맥적인 의미는 무시될 수 밖에 없겠죠? 이를 약간이라도 보완하고자 도입된 것이 n-gram입니다. n-gram은 연속된 n개의 단어를 하나의 토큰화 단위로 분리하는 것인데요, 예를 들어봅시다.

"Agent Smith knocks the door"를 2-gram(bigram)으로 만들면 (Agent, Smith), (Smith, knocks), (knocks, the), (the, door)와 같이 연속적으로 2개의 단어들을 순차적으로 이동하면서 단어들을 토큰화합니다.

 

 

 

[2] 스톱 워드 제거

스톱 워드(Stop word)란, 분석에 큰 의미가 없는 단어를 칭합니다. 예를 들어 영어에서 is, are, a, the 등은 문법적으로 필수적인 요소이지만 어떠한 큰 의미를 가지고 있지는 않죠? 한글에선 은, 는, 이, 가 정도가 Stop word겠네요. 이러한 Stop word는 분석에 중요하지 않지만 자주 등장합니다. 그렇기에 등장 빈도가 일반적으로 높은데, 기계는 이러한 등장 빈도를 '중요도'로 파악할 가능성이 있습니다. 따라서, 스톱 워드를 제거하는 과정은 굉장히 중요하다고 하네요.

 

NLTK는 스톱워드를 따로 저장하고 있는데요, 어떠한 것이 있는지 한번 확인해봅시다.

import nltk
nltk.download('stopwords')
print('영어 stop words 개수 : ', len(nltk.corpus.stopwords.words('english')))
print(nltk.corpus.stopwords.words('english')[:20]) # stop words 중 20개만 확인

 

이제는 stopwords를 필터링으로 제거해 분석을 위한 단어들만 추출해보겠습니다.

# stop words 제거하기.
stopwords = nltk.corpus.stopwords.words('english')

all_tokens = []
#위 예제에서 3개의 문장별로 얻은 word_tokens에 대해 스톱워드 제거하는 반복문
for sentence in word_tokens :
    filtered_words = []
    for word in sentence :
        word = word.lower() # 소문자로 변경
        if word not in stopwords :
            filtered_words.append(word)
    all_tokens.append(filtered_words)
    
print(all_tokens)

각 문장별로 is, this와 같은 스톱 워드가 필터링 되었음 알 수 있습니다.

 

 

 

[3] Stemming과 Lemmatization

많은 언어에서 문법적인 요소에 따라 단어가 다양하게 바뀌고있죠. 예를 들어, 영어에서 동사 원형 work에 대해 현재 진행형은 working, 과거형은 worked 등으로 형태가 변하죠. 한국어에서도 마찬가지입니다. 동사 원형 '한다'에 대해 과거형은 '했다' 등으로 바뀌죠? Stemming과 Lemmatization은 문법적 또는 의미적으로 변화하는 단어의 원형을 찾는 것입니다.

 

두 기능 모두 목적은 비슷하지만, Lemmatization이 Stemming보다 정교하며 의미론적인 기반에서 단어의 원형을 찾습니다. Stemming은 단순한 방법을 적용하기에 원래 단어에서 철자가 일부 훼손된 어근 단어를 추출하는 경향을 보입니다.

하지만, Lemmatization은 문법적인 요소와 의미적인 부분을 감안하기에 정확한 철자로 된 어근 단어를 찾습니다. 그렇기에 Lemmatization은 Stemming보다 실행시간이 더 오래 걸린다고 하네요. 둘의 차이를 코드를 통해 알아봅시다.

 

① Stemming

 

from nltk.stem import LancasterStemmer
stemmer = LancasterStemmer()
print(stemmer.stem('working'), stemmer.stem('works'), stemmer.stem('worked'))
print(stemmer.stem('amusing'), stemmer.stem('amuses'), stemmer.stem('amused'))
print(stemmer.stem('happier'), stemmer.stem('happiest'))
print(stemmer.stem('fancier'), stemmer.stem('fanciest'))

원형 단어와 비슷한 단어를 찾기는 했지만, 일부 철자가 훼손되는 것을 확인할 수 있습니다.

 

 

② Lemmatization

 

from nltk.stem import WordNetLemmatizer
import nltk
nltk.download('wordnet')

# Lemmatization 시, 보다 정확한 원형 단어 추출을 위해 단어의 '품사'를 입력해주어야함. 'v'는 동사, 'a'는 형용사
lemma = WordNetLemmatizer()
print(lemma.lemmatize('amusing', 'v'), lemma.lemmatize('amuses', 'v'), lemma.lemmatize('amused', 'v'))
print(lemma.lemmatize('happier', 'a'), lemma.lemmatize('happiest', 'a'))
print(lemma.lemmatize('fancier', 'a'), lemma.lemmatize('fanciest', 'a'))

Lemmatization은 원형 단어를 정확히 추출한 것을 볼 수 있습니다.

 

 

 

- 본 글은 파이썬 머신러닝 완벽 가이드 (권철민 지음)을 공부하며 내용을 추가한 정리글입니다. 개인 공부를 위해 만들었으며, 만약 문제가 발생할 시 글을 비공개로 전환함을 알립니다.