본문 바로가기
파이썬

파이썬 - 텍스트 데이터 전처리 파이프라인 (1) : 한국어 텍스트 전처리

by Tiabet 2023. 8. 19.

이번 포스팅에선 내가 텍스트 데이터를 전처리하기 위해 개발한 파이프라인에 대해 간략하게 글을 작성해보고자 한다. 1편과 2편으로 나누어서, 1편에선 전처리 과정에 대해, 2편에선 scikit-learn의 Pipeline 함수에 대해 정리해볼 예정이다.

 

전체 코드 ->

https://github.com/Tiabet/Project_Market/blob/master/%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%A0%84%EC%B2%98%EB%A6%AC/text_preprocessing_pipeline.py

 

전각 문자, 반각 문자 변환

전각 문자, 반각 문자의 개념은 다소 생소했다. 일반적으로 타이핑을 할 때 글자를 입력하는 정사각형 한 칸이 있다고 생각해보자. 글자가 정사각형 한 칸을 꽉 채우면 전각, 그렇지 못하면 반각 문자가 된다. 텍스트 데이터를 처리할 땐 전각 문자를 반각으로 변환해줘야 하는 과정을 거쳐야 하는데, 그 이유는 다음과 같다.

https://namu.wiki/w/%EC%A0%84%EA%B0%81%EA%B3%BC%20%EB%B0%98%EA%B0%81?from=%EC%A0%84%EA%B0%81%20%EB%AC%B8%EC%9E%90#fn-1 

 

전각과 반각 - 나무위키

이 섹션에서는 아스키 코드에 속하는 문자만을 주로 다룬다. 위에서도 서술했듯 한글이나 한자, 히라가나 등은 언제나 전각 문자이므로 따로 다루지 않는다. ①은 가로쓰기의 반각 문장 부호를

namu.wiki

전각 문자는 한국어로 쓰면 가독성도 좋지 않을 뿐더러, 이런 이유로 글자가 아스키 코드에 거의 100프로 반각 문자로 등록되어 있기 때문이다. 

 

전각 문자를 반각으로 변환하는 방법은 여러 가지가 있지만, 나는 아래 블로그에서 본 방법이 제일 간단하다고 생각하여 이 방법을 그대로 참고하였다.

 

https://blog.naver.com/PostView.naver?blogId=duswl0319&logNo=221516880642 

 

Python 전, 반자 변환 (전각, 반각 문자 변환)

자연어 처리, 텍스트 분석을 할 때 가끔 전각 문자(full-width charater)를 보게 된다. 편의를 위해 반각 ...

blog.naver.com

#전각문자 제거

import unicodedata

reviews = df['review']

for review in df['review']:
  review = unicodedata.normalize('NFKC', review)

reviews

전각-반각 변환은 사실 지금처럼 한국어 텍스트를 전처리할 때는 큰 필요는 없다는 것이 내 생각이지만, 외국어-특수문자 등을 다룰 때는 중요한 경우도 있고, 또 같은 글자여도 아스코드가 다른 경우도 있다고 해서 해보았다. 그리고 unicodedata는 파이썬에 내장되어 있는 패키지로, 그 중 normalize의 'nfkc' 에 대한 공식 문서를 읽어보니 같은 의미지만 표현이 다른 글자들을 하나로 정규화해주는 역할을 한다는 것을 알 수 있었다.

 

맞춤법, 띄어쓰기 교정

맞춤법과 띄어쓰기를 교정하는 패키지로는 네이버 맞춤법 검사기 모듈이기도 한 Hanspell을 사용했다.

https://wikidocs.net/92961

 

02-10 한국어 전처리 패키지(Text Preprocessing Tools for Korean Text)

유용한 한국어 전처리 패키지를 정리해봅시다. 앞서 소개한 형태소와 문장 토크나이징 도구들인 KoNLPy와 KSS(Korean Sentence Splitter)와 함께 유용하게 사…

wikidocs.net

여기에 hanspell에 대한 자세한 설명이 나온다.pycospacing도 사용해보려고 했는데 왠지 모르게 설치가 되지 않았다. Hanspell의 사용법은 아주 간단하다. 

 

# 띄어쓰기, 맞춤법 정정

from hanspell import spell_checker

spell_checked = []

for review in reviews:
  spelled_sent = spell_checker.check(review)
  text = spelled_sent.checked
  spell_checked.append(text)

spell_check를 가져온 뒤, check 함수를 사용하면 알아서 검사 결과를 반환해준다. check 함수의 결과에는 몇 개나 틀렸는지, 어디서 틀렸는지 등에 대한 정보도 함께 있다. 나는 고쳐진 문장 자체에 관심이 있었으므로 정정 후 문장이 담겨있는 checked 를 불러왔다.

 

공식문서 ->

https://github.com/ssut/py-hanspell

 

GitHub - ssut/py-hanspell: 파이썬 한글 맞춤법 검사 라이브러리. (네이버 맞춤법 검사기 사용)

파이썬 한글 맞춤법 검사 라이브러리. (네이버 맞춤법 검사기 사용). Contribute to ssut/py-hanspell development by creating an account on GitHub.

github.com

 

정규식 적용

이번 전처리 과제에서 가장 시간이 많이 들은 부분이 정규식을 이용한 전처리 부분이었다. 처음엔 이런 식의 코드를 짰다.

 

# 정규식 사용

import re

re_checked = []

for text in df_preprocessed['spell_checked']:
  only_BMP_pattern = re.compile("["
        u"\U00010000-\U0010FFFF"  #BMP characters 이외
                           "]+", flags=re.UNICODE)
  text = only_BMP_pattern.sub(r'', text)
  text = re.sub(r'[ㄱ-ㅎㅏ-ㅣ0-9]+', '', text)
  text = re.sub('ᄒ+', '', text)
  text = re.sub('[ෆ⃛❤❤❤♥♡】૮₍˶•⑅₎ა]', '', text)
  text = re.sub('[-=+,#/\?^.@*\";※~ㆍ!』‘|\<\>\[\]\_`\'…》\”\“\’·]', ' ', text)
  text = re.sub(r':[)D]|:[(]','', text)
  text = re.sub(r':','', text)
  text = re.sub(r'[a-zA-Z]{1,2}', '', text)
  text = re.sub(r'\s{2,}|\t', ' ', text)
  re_checked.append(text)

내가 일일이 텍스트 데이터들을 눈으로 봐가면서 지워야 할 것들을 다 입력한 것이다... 하지만 직접 경험해보니 이런 방법은 말그대로 엄청난 노가다이다. 물론 이런 과정이 태스크에 따라 필요할 수 있겠으나, 내가 하고자 했던 태스크는 "한국어와 영어 단어, 그리고 특수문자 중 괄호를 제외하고 모든 텍스트 지우기" 였기 때문에 아래와 같은 코드가 훨씬 깔끔할 것이다. (양식이 약간 다르다.)

def apply_regex(text): 
    text = re.sub(r'[^ 가-힣a-zA-Z\(\):]','',text)
    text = re.sub(r'[a-zA-Z]{1,2}', '', text)
    text = re.sub(r':\s?[)D]|:\s?\(', '', text)
    return text

이제 코드 설명을 하자면,

1) re.sub은 첫 번째 파라미터에 있는 문자들을 두 번째 파라미터로 대체한다는 의미다. 세 번째 파라미터는 적용할 string 을 의미한다.

2) r은 백슬래쉬 \ 를 이스케이프 문자 처리한다. 이스케이프 문자, 메타 문자 등에 대한 설명은 내용이 길어져서 우선 다른 포스팅으로 대체한다. 이와 관련해 여러 실험을 해봤는데, 후에 다른 포스팅으로 실험 내용을 정리해보고자 한다.

http://www.ktword.co.kr/test/view/view.php?m_temp1=5851 

 

정규표현 메타 문자

  Metacharacter   정규표현 메타 문자(2022-06-15)

www.ktword.co.kr

3) ^는 "뒤에 오는 문자들을 제외하고" 의 의미를 갖는다. 첫 번째 정규식에서 나는 공백, 한글 단어 (ㅋ, ㅏ 같은 단글자 제외), 알파벳 소문자, 대문자 그리고 괄호를 제외, 그리고 : 를 하고 모두 포함시켰다.

4) 다른 영어단어들은 모두 살리되 한 글자, 두 글자의 영단어들은 모두 삭제했다.

5) :), :( 같은 이모티콘을 모두 지우기 위해  사용한 패턴이다. /s? 는 여백 0칸 혹은 1칸을 의미한다. 

 

정규식 부분을 쓰다가 나도 헷갈리는 부분이 생겨서 이거저거 실험을 해보니, r이 없거나, \( \) 말고 ( ) 을 사용해도 특정 상황이 아니면 문제가 발생하지 않는 것 같다. 이에 대해선 다른 실험 포스팅에서 다루어보도록 하겠다.

 

 

아마 내가 진행한 태스크 말고 다른 태스크를 목적으로 하더라도 위 코드들이 범용적으로 적용될 수 있지 않을까, 생각한다. 추가적인 Pipeline에 관한 내용은 다음 포스팅에서 다루어보겠다.