본문 바로가기

NLP

2. 텍스트를 숫자로 - 인코딩

컴퓨터는 당연하게도 텍스트보다 숫자를 훨씬 더 잘 처리한다. 

 

이를 위해 자연어 처리에는 텍스트를 숫자로 바꾸는 여러가지 기법들이 존재하는데, 

 

보통은 단어들을 벡터로 만들어서 문제를 해결하고자 한다.

 

프로세스는 다음과 같다

 

1. 단어집합을 만듦

2. 단어 집합에 고유한 정수를 부여 (정수인코딩)

3. 숫자로 바뀐 단어들을 벡터로 다룸 (원-핫 인코딩)

 

이전 포스팅에서 이어지는 내용입니다!

https://rhks13.tistory.com/7

 

1. NLP의 뿌리, 텍스트 전처리

텍스트 전처리란 풀고자 하는 문제의 용도에 맞게 텍스트를 사전에 처리하는 작업을 말한다. 카레를 만들때 당근을 채 썰면 안되는 것 처럼, task에 알맞은 처리과정을 거쳐야한다. 코퍼스(대량

rhks13.tistory.com


1. 단어집합 만들기

우선 단어집합은 서로 다른 단어들의 집합을 말한다.

 

주의할점은 book과 books 같이 단어의 변형 형태도 다른 단어로 간주해버린다는 것

 

무튼 이렇게 텍스트(코퍼스)에 존재하는 모든 단어를 중복없이 모아놓으면 이를 단어집합이라고 명명한다.

 

2. 정수 인코딩

단어집합 내에 존재하는 단어들에 각각 정수 인덱스를 부여하는 과정이다.

 

보통 단어를 빈도수 순으로 정렬한 후, 빈도수가 높은 순대로 낮은 인덱스를 부여한다.

 

3. 원-핫 인코딩

단어집합의 크기를 벡터의 차원으로 고정하고, 

 

표현하고 싶은 단어의 인덱스에 1의값, 다른 인덱스에는 0을 부여하는 방식이다.

 

이렇게 표현된 벡터를 원-핫 벡터라고 한다.

 

원핫인코딩의 한계

  • 단어의 개수가 늘어날수록, 각각의 벡터의 크기가 커짐(차원이 늘어남) -> 비효율적
  • 단어의 유사도를 표현할 수 없어 -> 검색시스템 등에서 매우 큰 문제

이를 위해서 보통 워드 임베딩이라는 기법을 사용하는데, 

 

이는 추후에 알아보도록 하고 

 

예시를 통해서 프로세스를 한번 경험해보도록 하자

 


1. 단어집합 만들기 & 정수 인코딩

from nltk.tokenize import sent_tokenize
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords

raw_text = "A barber is a person. a barber is good person. a barber is huge person. he Knew A Secret! The Secret He Kept is huge secret. Huge secret. His barber kept his word. a barber kept his word. His barber kept his secret. But keeping and keeping such a huge secret to himself was driving the barber crazy. the barber went up a huge mountain."

# 문장 토큰화
sentences = sent_tokenize(raw_text)
print(sentences)

nltk에서 문장 토크나이저, 워드 토크나이저, 불용어 모듈을 불러온 후,

위키독스의 예시를 그대로 집어넣었다

 

우선 문장 토큰화를 시도하기위해 sent_tokenzie를 쓰는데

다음과 같은 에러가 발생할 것이다.

 

당황하지 않고 하라는대로 nltk.download('punkt')를 실행해주면 된다.

 

nltk라이브러리를 사용하는데 있어 이러한 상황이 자주 발생하게 될텐데,

 

그럴때마다 받으라는 리소스를 잘 받아주면 된다.

 

preprocessed_sentences = []
stop_words = set(stopwords.words('english'))

for sentence in sentences:
    # 단어 토큰화
    tokenized_sentence = word_tokenize(sentence)
    result = []

    for word in tokenized_sentence: 
        word = word.lower() # 모든 단어를 소문자화하여 단어의 개수를 줄인다.
        if word not in stop_words: # 단어 토큰화 된 결과에 대해서 불용어를 제거한다.
            if len(word) > 2: # 단어 길이가 2이하인 경우에 대하여 추가로 단어를 제거한다.
                result.append(word)
    preprocessed_sentences.append(result) 
print(preprocessed_sentences)

앞선 포스팅에서 소개했었던 토큰화, 정규화, 정제가 모두 담긴 코드이다.

 

이를통해서 전처리된 문장들을 반환한다.

 

[['barber', 'person'], ['barber', 'good', 'person'], ['barber', 'huge', 'person'], ['knew', 'secret'], ['secret', 'kept', 'huge', 'secret'], ['huge', 'secret'], ['barber', 'kept', 'word'], ['barber', 'kept', 'word'], ['barber', 'kept', 'secret'], ['keeping', 'keeping', 'huge', 'secret', 'driving', 'barber', 'crazy'], ['barber', 'went', 'huge', 'mountain']

이후 nltk의 FreqDist 모듈을 이용해 가장 빈도수가 높은 상위 5개의 단어로

 

단어집합을 생성했다.

from nltk import FreqDist
import numpy as np


vocab = FreqDist(np.hstack(preprocessed_sentences)) # np.hstack으로 문장 구분을 제거

vocab_size = 5
vocab = vocab.most_common(vocab_size) # 등장 빈도수가 높은 상위 5개의 단어만 저장
print(vocab)
[('barber', 8), ('secret', 6), ('huge', 5), ('kept', 4), ('person', 3)]

이제 enumerate를 이용해서 높은 빈도수를 가진 단어일수록 낮은 정수 인덱스를 부여한다

=> 정수 인코딩을 수행한다

word_to_index = {word[0] : index for index, word in enumerate(vocab)}
print(word_to_index)
{'barber': 0, 'secret': 1, 'huge': 2, 'kept': 3, 'person': 4}

 

해당 방식 외에도 keras를 사용해 모든 과정 수행 가능하다.

2. 원-핫 인코딩

다음과 같은 함수를 통해서 원-핫 인코딩을 수행한다.

def one_hot_encoding(word, word_to_index):
  one_hot_vector = [0]*(len(word_to_index))
  index = word_to_index[word]
  one_hot_vector[index] = 1
  return one_hot_vector
one_hot_encoding('barber', word_to_index)

의 결과는  [1, 0, 0, 0, 0]으로, 원-핫 인코딩이 정상적으로 수행된것을 확인할 수 있다.

 

앞서 설명했지만 이러한 방식에는 분명한 한계점이 존재한다.

 

다음 포스팅에서 워드임베딩을 통해 이러한 한계를 어떤식으로 극복하는지 확인해 볼 것이다

'NLP' 카테고리의 다른 글

3. 카운트 기반 단어 표현  (1) 2023.03.05
1. NLP의 뿌리, 텍스트 전처리  (0) 2023.02.28
자연어 처리 워크플로우  (0) 2023.02.19