[NLP] 한국어 자연어 전처리

민정·2022년 8월 8일
4

NLP

목록 보기
1/6

한국어 자연어 전처리 과정 정리

영어 같은 경우는 , 전처리 과정이 생각보다 단순하였는데 한국어로 전처리를 하려니 생각보다 어려웠다 .

리뷰데이터 분석을 진행하였는데 생각보다 전처리 과정이 복잡하였다
리뷰데이터는 오타도 많고, 신조어 , 외래어 등등 처리해야할게 많을 뿐더러 한글의 특성상 품사에 따라 ,문장의 띄어쓰기에 따라 의미가 쉽게 변하기 때문에 전처리 과정이 매우 중요했다

이제까지 수많은 시도를 거쳐 최최최종의 형식으로 정리한 전처리 흐름 및 사용 라이브러리를 정리한다.

불용어 처리

  • 기초적인 전처리
  • 크롤링한 데이터일경우 html, tag 제거
  • 숫자, 영어 등 필요하지 않은 문자 및 이모티콘 제거
  • “@%*=()/+ 와 같은 punctation 문장 부호 제거
punct = "/-'?!.,#$%\'()*+-/:;<=>@[\\]^_`{|}~" + '""“”’' + '∞θ÷α•à−β∅³π‘₹´°£€\×™√²—–&'
punct_mapping = {"‘": "'", "₹": "e", "´": "'", "°": "", "€": "e", "™": "tm", "√": " sqrt ", "×": "x", "²": "2", "—": "-", "–": "-", "’": "'", "_": "-", "`": "'", '“': '"', '”': '"', '“': '"', "£": "e", '∞': 'infinity', 'θ': 'theta', '÷': '/', 'α': 'alpha', '•': '.', 'à': 'a', '−': '-', 'β': 'beta', '∅': '', '³': '3', 'π': 'pi', } 


def clean(text, punct, mapping):
    for p in mapping:
        text = text.replace(p, mapping[p])
    
    for p in punct:
        text = text.replace(p, f' {p} ')
    
    specials = {'\u200b': ' ', '…': ' ... ', '\ufeff': '', 'करना': '', 'है': ''}
    for s in specials:
        text = text.replace(s, specials[s])
    
    return text.strip()


import re


def clean_str(text):
    pattern = '([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)' # E-mail제거
    text = re.sub(pattern=pattern, repl='', string=text)
    pattern = '(http|ftp|https)://(?:[-\w.]|(?:%[\da-fA-F]{2}))+' # URL제거
    text = re.sub(pattern=pattern, repl='', string=text)
    pattern = '([ㄱ-ㅎㅏ-ㅣ]+)'  # 한글 자음, 모음 제거
    text = re.sub(pattern=pattern, repl='', string=text)
    pattern = '<[^>]*>'         # HTML 태그 제거
    text = re.sub(pattern=pattern, repl='', string=text)
    pattern = '[^\w\s\n]'         # 특수기호제거
    text = re.sub(pattern=pattern, repl='', string=text)
    text = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]','', string=text)
    text = re.sub('\n', '.', string=text)
    return text 

Tokenize

  • 자연어 처리에서는 텍스트를 '토큰 단위' 로 구분한다
    한국어에서는 띄어쓰기가 텍스트의 의미를 구분하는데 영향을 주기 때문이다
    그렇지만 문맥이 없이 단순 띄어쓰기로만 토큰을 구분한다면, 단순히 단어로만 구분되어 문장 전체의 의미 파악이 어려워져 띄어쓰기에 따라 분석이 제대로 되지 않을 수도 있다.
  • 띄어쓰기를 해주는 오픈 라이브러리가 존재하지만 문제점 존재한다.
    - 라이브러리별로 뉴스같이 정제되고 전문적인 문체를 인식하는 라이브러리, 지식인 같은 대화체를 인식하는 라이브러리가 존재하여 서로 잘 안먹을 수 있다는 한계점 존재
  • 따라서 애초에 모든 공백을 없앤 후, 문맥에 따라 문장을 만드는 것이 좋은 방법
    -> '너무기대를 안했나봐'-> '너무기대를안했나봐' -> '너무 기대를 안 했나봐'

한국어 Tokenizer

1. PyKoSpacing

https://github.com/haven-jeon/PyKoSpacing
PyKoSpasing 사용 예시

```python
	pip install git+https://github.com/haven-jeon/PyKoSpacing.git

from pykospacing import spacing
print(spacing("김형호영화시장분석가는'1987'의네이버영화정보네티즌	10점평에서언급된단어들을지난해12월27일부터올해1월10일까지통계프로그램R과KoNLP패키지로텍스트마이닝하여분석했다."))
```

결과문
김형호 영화시장 분석가는 '1987'의 네이버 영화 정보 네티즌 10점 평에서 언급된 단어들을 지난해 12월 27일부터 올해 1월 10일까지 통계 프로그램 R과 KoNLP 패키지로 텍스트마이닝하여 분석했다.

띄어쓰기 말고, 문장 분리라는 것이 존재

:한국어 문장 분리 파이썬 라이브러리

  • 문장 분리의 경우 형태소 분석으로 종결어미를 구분한다던지, 문장의 CRF(Conditional Random Feild) 결과로 판단하는 방법이 존재한다.
    2. kss
 pip install kss
import kss
s = "회사 동료 분들과 다녀왔는데 분위기도 좋고 음식도 맛있었어요 다만, 강남 토끼정이 강남 쉑쉑버거 골목길로 쭉 올라가야 하는데 다들 쉑쉑버거의 유혹에 넘어갈 뻔 했답니다 강남역 맛집 토끼정의 외부 모습."
for sent in kss.split_sentences(s):
    print(sent)

결과문
회사 동료 분들과 다녀왔는데 분위기도 좋고 음식도 맛있었어요
다만, 강남 토끼정이 강남 쉑쉑버거 골목길로 쭉 올라가야 하는데 다들 쉑쉑버거의 유혹에 넘어갈 뻔 했답니다
강남역 맛집 토끼정의 외부 모습.

이런식으로 결과가 나온다. 리뷰 데이터 분석을 진행할 때에 간혹 리뷰를 상당히 길게 써주시는 고객분들이 있는데 ! 그중에 감정분석을 활용하여 필요한 문장만 추출해내고 싶을 때 kss 를 활용하여 한문장씩 읽어들인 후, 감정이 들어간 중요 문장만 따로 볼 수 있다.

3. py - hanspell
py-hanspell은 네이버 맞춤법 검사기를 이용한 파이썬용 한글 맞춤법 검사 라이브러리

pip install py-hanspell
from hanspell import spell_checker


result = spell_checker.check(u'안녕 하세요. 저는 한국인 입니다. 이문장은 한글로 작성됬습니다.')
result.as_dict()  # dict로 출력
{'checked': '안녕하세요. 저는 한국인입니다. 이 문장은 한글로 작성됐습니다.',
 'errors': 4,
 'original': '안녕 하세요. 저는 한국인 입니다. 이문장은 한글로 작성됬습니다.',
 'result': True,
 'time': 0.07065701484680176,
 'words': {'안녕하세요.': 2,
           '저는': 0,
           '한국인입니다.': 2,
           '이': 2,
           '문장은': 2,
           '한글로': 0,
           '작성됐습니다.': 1}}

결과문
-> result
Checked(result=True, original='안녕 하세요. 저는 한국인 입니다. 이문장은 한글로 작성됬습니다.', checked='안녕하세요. 저는 한국인입니다. 이 문장은 한글로 작성됐습니다.', errors=4, words=OrderedDict([('안녕하세요.', 2), ('저는', 0), ('한국인입니다.', 2), ('이', 2), ('문장은', 2), ('한글로', 0), ('작성됐습니다.', 1)]), time=0.10472893714904785)

checked 파라미터 값이 담고 있는 데이터가 맞춤법이 완료된 데이터 이다


Nomalizer (정규화)

반복되는 이모티콘이나 자모 ㅎㅎㅎ, ㅋㅋㅋㅋㅋ, 하하 같은 것들을 Nomalizer 시켜주는 라이브러리 존재

1. soynpl

!pip install soynlp
from soynlp.normalizer import *
print(repeat_normalize('와하하하하하하하하하핫', num_repeats=2))

Lemmatization(표제어 추출)

리뷰데이터 분석을 진행할 때 감성어 사전을 활용하여 감성 score 추출을 했었는데 , 이 과정에서 같은 의미의 동사/형용사를 표제어로 추출해야하는 과정이 필요했다.
우리가 진행한 실습은 NNP, NNG, VA 만 POS TAG 로 추출하였기 때문에 이 부분만 처리해주었다 !

def lemmatize(sentence):
    morphtags = komoran.pos(sentence)
    words = []
    for m, t in enumerate(morphtags) :
      k = t.get_pos()
      if k=='NNP' or k=='NNG' :
        words.append(t.get_morph())
      elif k=='VA' or k=='VV' :
        words.append(t.get_morph()+'다')
    return words

w_ = []
for i in range(len(sunstic)) :
  words = lemmatize(sunstic.iloc[i]['review'])
  w_.append(' '.join(words))
df['words'] = w_  
df = df[df['words']!='']

POS TAG

형태소 분석기에는 여러가지 종류가 있지만, 내가 진행하던 데이터는 리뷰데이터 였고, 이에 적합한 형태소 분석기 KOMORAN을 찾아 사용하였다 .

  1. KOMORAN
    KOMORAN은 타 형태소 분석기와 달리 여러 어절을 하나의 품사로 분석가능하여 고유명사(영화 제목, 음식점명 등)을 더욱 정확하게 분석이 가능하다
!pip install PyKomoran # 코모란 설치 

from PyKomoran import *
import re
komoran= Komoran(DEFAULT_MODEL['LIGHT'])
n_= []

for i in range(len(sunstic)):
  nouns = komoran.get_morphes_by_tags(sunstic.iloc[i]['review'], tag_list=['NNP', 'NNG','VA']) #추출할 tag 리스트 
  n_.append(' '.join(nouns))
df['nouns'] = n_
df = df[df['nouns']!='']

이런 흐름으로 여기까지 전처리를 했다면 어느정도 깔끔한 데이터를 볼 수 있다



살짝 회고의 시간을 가지자면
리뷰데이터 분석을 진행하여 의미있는 문장 한 문장을 추출하였다.
전처리 과정은

  1. 불용어처리
  2. 맞춤법 검사
  3. nomalize 정규화
  4. kss 한문장씩 나누어 저장
  5. 형태소 분석기로 명사 추출
  6. 감성분석으로 필요없는 문장 제외

까지 한 후 리뷰데이터 분석을 진행했을 때 깔끔하게 잘 진행되었던 것 같다 !
리뷰데이터 감성분석과 클러스터링에 대한 것은 차근차근 글을 올려 정리해야겠다

profile
공부 기록장

2개의 댓글

comment-user-thumbnail
2023년 5월 30일

감사합니다. 도움이 많이 됐습니다.

1개의 답글