Text Processing(2) - 데이터 전처리(Text Preprocessing)

2019. 1. 23. 00:24Udacity Nanodegree/Natural Language Processing

Text Normalization

  • 텍스트의 복잡도를 낮추기 위한 작업

  • 영어에서는 문장의 첫 글자는 대문자이다

  • 스타일 이슈때문에 단어를 모두 대문자로 쓰는 경우도 있다

  • 사람 입장에서는 이러한 차이를 두는 것이 충분히 근거가 있지만 기계가 단어를 보고 해석하기에는 이러한 차이를 두는 것은 의미가 없다.

  • 따라서 텍스트 처리를 위해 보통 모든 문자를 소문자로 두곤 한다.

  • NLP의 목적에 따라 punctuation을 없애버리기도 한다.

    • 마침표, 쉼표, 느낌표 등등

  • 이러한 방법은 문서 분류(document classification), 군집화(clustering)와 같이 세부적인 디테일이 그렇게 중요하지 않은 경우에 사용한다

  • 정규 표현식을 다음과 같이 사용한다.

    text = re.sub(r"[^a-zA-Z0-9]", " ", text)

    • a~z, A~Z, 또는 0~9가 아닌 문자를 모두 공백으로 치환한다.

    • 여기서 중요한 점은 아예 없애는 것이 아닌 공백으로 치환한다는 점이다.

      • 이는 문장의 형태를 최대한 유지하기 위함이다.

  • 정리하면, 소문자 변환이나 punctuation 제거는 가장 흔하게 쓰이는 Text normalization방법이다



Tokenization

  • Token은 Symbol을 세련된 말로 표현하는 방법이며, 뜻을 가지고 있는 상태로 더이상 쪼갤 수 없는 상태인 것들을 지칭한다

  • NLP의 경우 각각의 단어를 Token이라고 칭한다

    • 따라서 Tokenization이라고 하면 문장을 단어별로 나누는 작업을 칭한다

  • Text데이터에서 이러한 Tokenization을 가장 간단하게 해 볼수 있는 방법은 python의 split()을 통한 방법이다.

    • 이 경우, List형태의 단어 묶음을 받는다.

    • 기본적으로 ' '(스페이스, space)를 기준으로 나눈다.

      • 여기서는 tab이나 new line문자(\n)도 기준에 포함한다.

    • 또한 2개 이상의 공백도 무시함으로써 공백 문자를 받는 것을 방지한다.

    • 필요할 경우, 이러한 기준을 따로 설정하는 parameter가 있다

  • 여기까지 우리는 python의 빌트인(built-in) 함수를 통한 방법을 알아봤지만, 이 중에서 몇몇 방법은 NLTK 라이브러리를 사용한다면 훨씬 수월하게 진행할 수 있다.

    • NLTK: Natural Language Toolkit

  • 문장을 가장 수월하게 나눌 수 있는 방법에는 nltk.tokenize를 불러오는 방법이 있다.

    • from nltk.tokenize import word_tokenize

    • 이 경우, python의 split()과 비슷하게 동작하지만 좀더 스마트하게 작동한다.

      • punctuation이 문장 내 위치에 따라 다르게 취급된다.

  • 때론 텍스트 전체를 문장 단위로 나눠야 할 때도 있다.

    • 문장을 번역하고 싶을 경우에 이러한 작업이 발생한다.

    • from nltk.tokenize import sent_tokenize

    • 이렇게 문장을 나누고 나면 각 문장을 단어로 나누는 작업도 할 수 있다.

    • NLTK는 다른 여러가지 tokenizer를 제공한다.

      • 정규 표현식 기반

      • Tweet tokenizer

        • 트위터 핸들이나 해쉬태그나 이모티콘도 분류해준다.

  • 더 세부적인 내용을 살펴보고 싶다면 nltk.tokenize 내용을 살펴보자



Stop Word Removal

  • Stop word란 is, at, or, 등등... 과 같은 문장 내에서 크게 의미를 가지지 않는 단어들을 말한다.

  • 이러한 stop word를 제거해 주는 과정을 거치면서 우리가 작업해야 하는 단어의 종류를 줄일 수 있다.

    • 이런 과정을 통해 추후의 과정에서의 복잡성을 조금이라도 줄일 수 있다.

  • 예를 들면, dogs are the best라는 문장에서 are과 the를 빼면, dogs best만 남는다.

    • 이 단어들만 가지고도 충분히 문장이 긍정적인 감정을 가진다는 것을 볼 수 있다.

  • NLTK를 이용하면 어떤 단어들이 stop word인지 볼 수 있다.

    # List stop words
    from nltk.corpus import stopwords
    print(stopwords.words("english")) # stop words in English
    • 이러한 stop word의 corpus는 라이브러리나 프로그램에 따라 다르다.

    • 또한 용도에 따라서는 stop word가 아닐 수도 있게 된다.

  • stop word를 제거하기 위해 다음과 같은 코드를 사용한다.

    • words = [w for w in words if w not in stopwords.words("english")]

    • 문장을 리스트로 받아 그중 stop word에 해당하는 것들을 지워주는 코드



Part-of-Speech Tagging

  • PoS(Part-of-Speech)란 문장 내에서 단어의 품사를 말한다.

    • 명사, 동사, 대명사, 등등이 이에 포함된다.

  • 문장 내에서 단어가 어떻게 쓰였는지에 대해 살펴보는 것은 문장이 어떤것을 말하고자 하는지 이해하는데에 도움이 된다.

  • 또한 문장 내에서 단어와 단어간의 관계를 집어 살펴보거나, 단어들 간의 상호 참조와 같은 관계를 살펴보기에 용이하다.

  • NLTK는 이번에도 이러한 작업을 쉽고 편하게 만들어준다.

    • pos_tag함수를 통해 이러한 작업을 쉽게 할 수 있다.

from nltk import pos_tag

# Tag parts of speech (PoS)
sentence = word_tokenize("I always lie down to tell a lie")
pos_tag(sentence)



  • 잘 살펴본다면 알겠지만 같은 lie라는 단어도 문장의 위치에 따라 VBP(동사)와 NN(명사)로 구분되는 것을 확인할 수 있다.

    • 각 태그가 어떤 뜻인지 살펴보려면 NLTK 공식 문서를 확인해 보자

  • 이러한 PoS Tagging을 통해 문장 parsing을 할 수도 있다.

# Define a customer grammer
my_grammer = nltk.CFG.fromstring("""
S -> NP VP
PP -> P NP
NP -> Det N | Det N PP | 'I'
VP -> V NP | VP PP
Det -> 'an' | 'my'
N -> 'elephant' | 'pajamas'
V -> 'shot'
P -> 'in'
""")
parser = nltk.ChartParser(my_grammar)

# Parse a sentence
sentence = word_tokenize("I shot an elephant in my pajamas")
for tree in parser.parse(sentence):
   print(tree)
  • 위 코드를 진행하고 나면 다음과 같이 두가지의 다른 결과를 볼 수 있다.

  • 또한 위 결과가 이해가 잘 되지 않는다면 아래 코드를 통해 시각화를 직접 해볼수도 있다.

# Visualize parse trees
for tree in parser.parse(sentence):
   tree.draw()
  • 위 코드를 진행하면 아래와 같은 결과가 나온다.