부스트캠프 NLP 1주차 학습정리

1. 자연어 전처리

데이터를 이용해 우리의 목적(task)에 맞게 모델을 학습시키기 위해서 가장 중요한 것은 데이터의 품질입니다. Garbage-In Garbage-Out이라는 말이 있듯이, 낮은 품질의 데이터로 좋은 모델을 얻을 수는 없습니다.
그래서 이번 포스트에서는 여러 경로(공공기관, 웹크롤링, NLP관련 패키지(nltk, konlpy 등))를 통해 얻은 자연어를 어떤 처리를 통해 데이터의 품질을 향상시킬지에 대해 함께 공부해보겠습니다.

제 생각에 말뭉치를 처음 받았을 때, 자연어 전처리를 하는 과정은 다음과 같다고 생각합니다. 하지만 이 순서는 절대로 절대적인 것이 아니며, task에 따라 어떤 것은 생략되고, 어떤 것은 더 추가가 되어야 하는 등 과정에 변동성이 있다는 점을 먼저 말씀드리도록 하겠습니다.

1) 특수문자, 숫자 제거

나 오늘 치킨 먹었어 ^_^
어제 슈퍼에 가서 사과, 바나나, 딸기, 치킨을 샀어.

다음과 같은 말뭉치가 있다고 할 때, ^_,.과 같은 특수문자가 반드시 필요하지는 않습니다. 다음과 같은 특수문자를 vocab에 정의해둬야 하는 경우가 아니라면 제거하는 것이 좋습니다. (하지만 나의 task가 코딩 자동화, 환율 예측, 수식 자동화와 같은 경우라면 물론 특수문자를 제거하시면 안됩니다)

special_char_removed_corpus = re.sub("[^a-zA-Z0-9가-힣 \n]", "", corpus)

저는 다음과 같이 정규 표현식을 사용하여 특수문자를 제거하였습니다.

# 특수문자를 제거하기 전
제1장 총강
  제1조 ① 대한민국은 민주공화국이다.
②대한민국의 주권은 국민에게 있고, 모든 권력은 국민으로부터 나온다.
  제2조 ① 대한민국의 국민이 되는 요건은 법률로 정한다.
②국가는 법률이 정하는 바에 의하여 재외국민을 보호할 의무를 진다.
# 특수문자 제거 후
제1장 총강
  제1조  대한민국은 민주공화국이다
대한민국의 주권은 국민에게 있고 모든 권력은 국민으로부터 나온다
  제2조  대한민국의 국민이 되는 요건은 법률로 정한다
국가는 법률이 정하는 바에 의하여 재외국민을 보호할 의무를 진다

2) 맞춤법 검사

채팅으로 주고 받은 대화 또는 SNS에서 가져온 글들을 데이터로 사용하고 싶다면, 맞춤법이 틀린 경우가 많습니다. 그러한 경우 네이버에서 제공하는 Py-Hanspell 패키지를 이용해 맞춤법에 맞게 데이터를 클리닝할 수 있습니다. 하지만 여러가지 제약점이 있어서 얼마나 잘 활용될 수 있을지는 모르겠습니다.

!pip install git+https://github.com/ssut/py-hanspell.git

from hanspell import spell_checker

i = 0
hanspell_corpus = ""
while True:
    # 한 번에 500자까지 밖에 안됨..
    batch_corpus = special_char_removed_corpus[i:i+500]
    spelled_sent = spell_checker.check(batch_corpus)
    hanspell_sent = spelled_sent.checked
    hanspell_corpus += hanspell_sent
    i += 500
    if i == 4000:
        break
print(hanspell_corpus)

3) 불용어 제거

말뭉치에서 큰 의미를 가지지 않지만 빈도수는 굉장히 높은 단어들이 있습니다. 예를 들면, I, my, me, over, 조사, 접미사 같은 단어들은 문장에서는 자주 등장하지만 실제 의미 분석을 하는데는 거의 기여하는 바가 없는 경우가 있습니다.

불용어는 정해진 것이 아니기 때문에, 빈도수에 따라 의미없는 조사나 접미사 등을 리스트로 만들어 말뭉치에서 제거하도록 하면 됩니다. 영어같은 경우에는 불용어 리스트를 패키지에서 제공하기도 합니다.

from nltk.corpus import stopwords  
stopwords.words('english')[:10]
--------------------------------------------
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', 'your']    

한국어의 불용어 같은 경우에는 구글에서 불용어 목록을 검색해서 사용했습니다.

stop_list = ['가', '같이', '과', '까지', '께', '께서', '께서는', '들', '나', '나마', '는', '는커녕', '다가', '더러', '도', '든', '든지', '라고', '라는', '라니', '라야', '라는', '로', '로는', '로부터', '로서는마는', '마다', '마저', '만', '만은', '만치', '말고', '며', '밖에', '보고부터', '서', '서부터', '야', '야만', '야말로', '에', '에게', '에게로', '에게서', '에는', '에서는', '에서부터', '에서처럼', '에의', '와', '으로부터', '으로서', '으로써', '은', '은커녕', '을', '의', '이', '이고', '이든지', '이라', '이라고', '이라도', '이라든지', '이라서', '이라야', '이라야만', '며', '이면', '이야', '이야말로', '이여', '인들', '인즉', '일랑', '일랑은', '조차', '처럼', '치고', '치고는', '커녕', '토록', '하고', '하고는', '한테', '한테로', '한테서']
cleaned_corpus = []
for word in corpus:
    if word not in stop_list:
        cleaned_corpus.append(word)
print(cleaned_corpus)

4) 어간, 표제어 추출

어간 추출과 표제어 추출은 서로 다른 단어를 하나의 뿌리 단어로 통일시키는 작업입니다. 둘의 차이점은 어간 추출은 품사가 보존되지 않는다는 것이고, 표제어 추출은 품사가 보존됩니다.

watched, watching, watches -> watch

보통 어간, 표제어 추출은 패키지에서 제공하는 tokenize 단계에서 인자 stem에 True를 주면 됩니다.

from konlpy.tag import Okt
okt = Okt()

stem_tokenized_corpus = okt.morphs(corpus, stem=True)  

2. 자연어 토큰화

말뭉치를 전처리하고 난 후에는 특정 단위로 구분하기 위해 토큰화(tokenization)을 진행합니다. 크게 문장 단위, 어절 단위(띄어쓰기), 형태소 단위(의미 단위), 음절 단위(문자 단위)가 있습니다.

보통 영어는 어절 단위로 많이 토큰화를 하고, 한국어는 형태소 단위로 토큰화를 많이 진행합니다.

머릿결 -> 머리 + 결
우리는 -> 우리(자립 형태소) + 는(의존 형태소)
# 영어
from nltk.tokenize import word_tokenize
text="I am actively looking for Ph.D. students. and you are a Ph.D. student."
print(word_tokenize(text))
---------------------------------------------------------------------------------
['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are', 'a', 'Ph.D.', 'student', '.']
# 한국어
from konlpy.tag import Okt  
okt=Okt()  
print(okt.morphs("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
------------------------------------------------------------------
['열심히', '코딩', '한', '당신', ',', '연휴', '에는', '여행', '을', '가봐요']  

토큰화를 한 후, fly(파리, 날다)와 같은 동음이의어 문제를 해결하기 위해 품사 태깅을 많이 합니다.

from nltk.tag import pos_tag
x=word_tokenize(text)
pos_tag(x)
--------------------------------------------------------------------
[('I', 'PRP'), ('am', 'VBP'), ('actively', 'RB'), ('looking', 'VBG'), ('for', 'IN'), ('Ph.D.', 'NNP'), ('students', 'NNS'), ('.', '.'), ('and', 'CC'), ('you', 'PRP'), ('are', 'VBP'), ('a', 'DT'), ('Ph.D.', 'NNP'), ('student', 'NN'), ('.', '.')]
print(okt.pos("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
----------------------------------------------------------------------
[('열심히','Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('연휴', 'Noun'), ('에는', 'Josa'), ('여행', 'Noun'), ('을', 'Josa'), ('가봐요', 'Verb')]  

Tags:

Categories:

Updated: