데이터마이닝/텍스트마이닝

[텍스트 전처리] 정제, 정규화

DS지니 2021. 12. 15. 14:18
728x90
반응형
공부내용 참고사이트 : 위키독스 딥러닝을 이용한 자연어 처리 입문 https://wikidocs.net/21698

 

*텍스트 전처리 - 용도에 맞게 텍스트를 사전에 처리하는 작업

 

Corpus(말뭉치)에서 용도에 맞게 토큰을 분류하는 작업을 토큰화(tokenization)라고 한다.

만약 정제되지 않은 코퍼스 그대로 토큰화를 진행한다면 원하는 결과를 얻는데 어려움이 있을 수 있다. 

전처리를 통해 상황과 목적에 맞게 원본 데이터를 갈고 닦아준다면 좀 더 유의미한 결과를 얻을 수 있을 것이다.

텍스트 전처리 중 정제(Cleaning)와 정규화(Normalization)에 대해 알아보자.

 

텍스트 전처리
정제 정규화
- 등장 빈도가 적은 단어 제거
- 길이가 짧은 단어 제거
- 불용어 제거
- 어간추출과 표제어추출
- 소문자 변환

 

 


 

 

1. 정제 (Cleaning) 

- 코퍼스의 노이즈 데이터를 제거한다. 즉, 토큰화 작업에 방해가 되는 부분들을 없앤다.

- 토큰화 전에 정제를 하기도 하지만, 토큰화 작업 이후에도 여전히 남아있는 노이즈들을 제거하기 위해 지속적으로 이뤄지기도 한다. 

- 노이즈 데이터는 특수 문자같은 아무 의미도 갖지 않는 글자들을 의미하기도 하지만, 분석하고자 하는 목적에 맞지 않는 불필요한 단어들을 말하기도 한다.

- 불용어 제거, 빈도 적은 단어제거, 길이 짧은 단어 제거 등

- 완벽한 정제 작업은 어렵기에 , 대부분의 경우 어느 선에서 합의점을 찾기도 한다.

 

 

1) 등장 빈도가 적은 단어 제거 (Removing Rare words)

빈도 수가 너무 적어 자연어 처리에 도움이 되지 않는 단어들을 제거한다.

 

 

2) 길이가 짧은 단어 제거 (Removing words with a very short length)

영어권에서는 길이가 짧은 단어들은 구두점들을 포함해 대부분 불용어(it, at, to, on, in, by 등)에 해당되어 유의미한 제거가 가능하다.

하지만 한국어에서는 이런 방법이 크게 유효하지 않을 수도 있다.

# 1-2개 길이의 단어를 제거하는 정규표현식
shortword = re.compile(r'\W*\b\w{1,2}\b')
print(shortword.sub('',text))

 

 

3) 불용어 (Stopword)

갖고 있는 데이터에서 유의미한 단어 토큰만을 선별하기 위해서 큰 의미가 없는(자주 등장하지만 분석에 큰 도움이 되지 않는) 단어 토큰을 제거하는 작업이 필요하다. (ex. I, my, me, over, 조사, 접미사 등)

 

자연어 처리를 위한 파이썬 패키지인 NLTK에서는 100여개 이상의 영어 단어들을 불용어로 미리 정의하고 있으며, 그 외 사용자가 직접 불용어를 정의할 수도 있다.

# NLTK 정의된 불용어 확인하기
from nltk.corpus import stopwords

stop_words_list = stopwords.words('english')
print('불용어 개수 :', len(stop_words_list))
print('불용어 10개 출력 :', stop_words_list[:10])

#결과
> 불용어 개수 : 179
> 불용어 10개 출력 : ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're"]
# NLTK로 불용어 제거해보기
from nltk.tokenize import word_tokenize

ex = "Family is not an important thing. It's everything."
stop_words = set(stopwords.words('english'))

word_tokens = word_tokenize(ex)

result = []
for word in word_tokens:     # 1)단어 토큰 나누기
  if word not in stop_words: # 2)만약 단어가 불용어사전에 포함되지 않는다면
    result.append(word)      # 3)리스트에 담기

print('불용어 제거 전 :',word_tokens)
print('불용어 제거 후 :', result)

#결과
> 불용어 제거 전 : ['Family', 'is', 'not', 'an', 'important', 'thing', '.', 'It', "'s", 'everything', '.']
> 불용어 제거 후 : ['Family', 'important', 'thing', '.', 'It', "'s", 'everything', '.']
# 한국어 불용어 사용자 정의 & 제거
from konlpy.tag import Okt

okt = Okt()
example = "한국어에서 불용어를 제거하는 방법으로는 간단하게는 토큰화 후에 조사, 접속사 등을 제거하는 방법이 있습니다."
stop_words = "에서 를 으로는 는 에 화 을 하는 이 습니 . , "

stop_words = set(stop_words.split(' '))
word_tokens = okt.morphs(example)

result = [word for word in word_tokens if not word in stop_words]

print("불용어 제거 전 :",word_tokens)
print("불용어 제거 후 :", result)

#결과
> 불용어 제거 전 : ['한국어', '에서', '불', '용어', '를', '제거', '하는', '방법', '으로는', '간단하게는', '토큰', '화', '후', '에', '조사', ',', '접속사', '등', '을', '제거', '하는', '방법', '이', '있습니다', '.']
> 불용어 제거 후 : ['한국어', '불', '용어', '제거', '방법', '간단하게는', '토큰', '후', '조사', '접속사', '등', '제거', '방법', '있습니다']

불용어가 많은 경우에는 코드 내에서 직접 정의하지 않고, txt 파일이나 csv 파일로 정리해놓고 이를 불러와서 사용하기도 한다.

 

 


 

 

 

2. 정규화 (Normalization) 

- 표현 방법이 다른 단어들을 통합시켜 같은 단어로 만들어준다.

- 예)US, USA는 같은 의미이므로, 하나의 단어로 정규화 할 수 있다.

- 어간추출, 표제어 추출, 소문자 변환 등

 

 

 

1) 어간 추출(Stemming), 표제어 추출(Lemmatization)

서로 다른 단어들이지만, 하나의 단어로 일반화 시켜 문서 내에 추출되는 단어의 개수를 줄이는 방법인 어간 추출과 표제어 추출이 있다. 전처리 시점에서는 코퍼스로부터 복잡성 줄이는데 의의가 있고, 단어 빈도수를 이용한 자연어 처리 문제(Bag of Words)에서는 문서 내의 단어 수를 줄이는데 의의가 있다.

 

어간 추출과  표제어 추출의 차이점은 표제어 추출은 문맥을 고려하며 해당 단어의 품사 정보를 보존한다 (POS태그 보존). 하지만 어간 추출은 품사 정보가 보존되지 않는다.(POS태그 고려X) 그래서 어간 추출을 할 경우 사전에 존재하지 않는 단어일 경우가 많다.

 

Stemming Lemmatization
am → am
the going → the go
having → hav

am → be
the going → the going
having → have


 

*형태소 : 의미를 가진 가장 작은 단위 (어간+접사)

*형태학(morphology) : 형태소로부터 단어를 만들어가는 학문

*어간(stem) : 단어의 의미를 담고 있는 단어의 핵심 부분

*접사(affix) : 단어에 추가적인 의미를 주는 부분

*표제어(Lemma) :  기본 사전형 단어

 

 

 

> 표제어 추출(Lemmatization)

 

표제어 추출은 단어들이 다른 형태를 가지더라도, 그 뿌리 단어를 찾아가서 단어의 개수를 줄일 수 있는 지 판단한다.

즉, 표제어 추출은 표제어를 만들기 위해 시간과 수량과 관련된 형식은 모두 제거된다. (명사의 복수형은 단수형으로, 동사의 시제/분사는 모두 현재시제로 돌아감. 그 외 케이스로 특징을 나타내거나 성별 등 추출) 

ex) am,are,is의 표제어는 be이다.

 

표제어 추출을 하는 가장 섬세한 방법은 단어의 형태학적 파싱을 먼저 진행하는 것이다.

*형태학적 파싱 : 형태소 즉, 어간과 접사를 분리하는 작업 ex) cats = cat(어간) + -s(접사) 

 

 

NLTK에서 표제어를 추출할 수 있다.

아래 코드 예시를 보면 표제어 추출은 단어의 형태가 적절히 보존되는 양상을 보이는 특징이 있다.

import nltk
nltk.download('wordnet')

from nltk.stem import WordNetLemmatizer
le = WordNetLemmatizer()
wrod = "lives"
print(le.lemmatize(word))

#결과
> life

- lives를 입력한 결과 life라는 표제어가 추출됨을 확인하였다.

 

word = "watched"
print(le.lemmatize(word))
print(le.lemmatize(word,'v'))

#결과
> watched 
> watch

- 하지만 표제어 추출이 잘 되지 않는 경우가 많다. 사실 표제어추출기(lemmatizer)는 본래 단어의 품사 정보를 알아야만 정확한 결과를 얻을 수 있기 때문에, 'v'처럼 단어 뒤에 품사의 정보를 같이 입력한다면 보다 정확한 표제어를 추출할 수 있다.

 

 

 

 

> 어간 추출(Stemming)

 

어간(단어의 의미를 담고 있는 단어의 핵심 부분)을 추출하는 과정이다.

Stemming은 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업으로, 어간 추출 후 나오는 결과가 단어는 사전에 존재하지 않는 단어일 수도 있다.

 

NLTK에서 어간 추출 작업을 할 수 있다. 예를 들어 Porter 알고리즘의 어간 추출은 아래와 같은 규칙들을 가진다.

from nltk.stem import PorterStemmer
stemmer = PorterStemmer()

words = ['formalize', 'allowance', 'electricical']
print([stemmer.stem(w) for w in words])

#결과
> ['formal', 'allow', 'electric']

ex) alize -> al / ance -> 제거 / ical -> ic

* 그 외 Porter stemmer 규칙 (The Porter Stemming Algorithm) : https://tartarus.org/martin/PorterStemmer/

 

 

어간 추출 속도는 표제어 추출보다 일반적으로 빠르며, 포터 어간 추출기는 정밀하게 설계되어 정확도가 높아 영어 어간 추출기로 괜찮다.

NLTK에서는 Poter Stemmer 이외에도 Lancaster Stemmer(랭커스터 스태머) 알고리즘 또한 지원한다.

from nltk.stem import PorterStemmer
from nltk.stem import LancasterStemmer
stemmer = PorterStemmer()
lan_stemmer = LancasterStemmer()
words = ['policy', 'fly', 'dies', 'has', 'organization']
print('PorterStemmer :', [stemmer.stem(w) for w in words])
print('LancasterStemmer :', [lan_stemmer.stem(w) for w in words])

# 결과
> PorterStemmer : ['policyfli', 'die', 'ha', 'organ']
> LancasterStemmer : ['policyf', 'die', 'has', 'org']

두 stemmer의 알고리즘은 서로 다르기 때문에 결과가 다르다. 이처럼 이미 알려진 알고리즘을 사용하고자 할 때는 각 stemmer를 적용해보고 어떤 것이 적합한지 판단 후에 사용하면 된다.

 

 

 

* 한국어 어간 추출

품사
체언 명사, 대명사, 수사
수식언 관형사, 부사
관계언 조사
독립언 감탄사
용언 동사, 형용사

- 5언 9품사 구조

- 용언(동사,형용사)은 어간(stem)과 어미(ending)의 결합으로 구성된다. 이를 활용(conjugation)이라고 한다.

- 활용은 규칙 활용과 불규칙 활용으로 나뉜다.

- 어간(stem) : 용언을 활용할 때, 원칙적으로 모양이 변하지 않는 부분을 말한다. 때론 모양이 바뀔 수도 있음 (ex. 긋다.긋고,그어서,그어라)

- 어미(ending) : 용언의 어간 뒤에 붙어 활용하면서 변하는 부분을 말한다. 여러 문법적 기능을 수행.

  규칙활용 불규칙활용
정의 어간이 어미를 취할 때, 어간 모습이 일정함 어간이 어미를 취할 때, 어간 또는 어미의 모습이 변함
추출 방법 규칙 기반으로 어미를 단순히 분리해준다. 어간이 바뀌므로 단순한 분리만으로 어간 추출이 되지 않고 좀 더 복잡한 규칙이 필요하다.
예시 - 잡다 -> 잡+아, 잡+고
- 믿다 -> 믿+음
- 굳다 -> 굳+을
- 깨닫다 -> 깨달아
- 긋다 -> 긋고, 그어서,그어라
- 그러다 -> 그러+어 -> 그래

 

 

 

 

 

2) 소문자변환

 

영어권의 경우, 대소문자를 통합해 추출되는 단어의 개수를 줄일 수 있다.

하지만 때에 따라 대소문자를 구별해야 하는 경우도 있기 때문에 무작정 통합해서는 안된다.

예를 들면 미국의 'US'와 우리를 뜻하는 'us'는 구분되어야 하고, 회사이름이나 사람이름 등은 대문자로 유지되는 것이 옳다. 이럴 때는 일부만 소문자로 변환시켜야 한다.  

방법1) 규칙을 정해 문장의 맨 앞에 나오는 단어만 소문자로 바꾸고, 나머지는 바꾸지 않는다.

방법2) 더 많은 변수를 사용해 소문자 변환을 위한 머신러닝 시퀀스 모델을 사용한다.

 

하지만 결국 그냥 모든 코퍼스를 소문자로 바꾸는 것이 더 실용적인 해결책이 되기도한다.

즉, 상황에 맞게 더 나은 방법을 사용하자..

 

 

*정규 표현식(Regular Expression)

코퍼스의 노이즈 데이터 특징을 잡아낼 수 있다면, 정규 표현식을 통해 이를 제거할 수 있다.

html 태그에 따라 정규표현식을 사용해 크롤링 하는 방식처럼, 코퍼스 내에 계속해서 등장하는 글자들을 규칙에 기반해 한 번에 제거하는 방식으로 유용하다.

 

** 이어서 정규식 따로 포스팅하기

 

 

 

 

 

 

 

 

 

728x90
반응형