4 분 소요

kocw 자연어처리 강의

이 포스팅은 위의 강의와 자료를 보고 정리한 게시글입니다..

정수 인코딩

  • 자연어를 컴퓨터가 이해할 수 있는 형태로 인코딩하는 과정

패딩(padding)

  • 자연어를 컴퓨터가 이해할 수 있는 숫자 형태로 인코딩하는 과정에서 문장들의 길이를 모두 동일하게 맞추는 작업
  • 컴퓨터는 길이가 동일한 문장을 하나의 행렬로 만들어 병렬적으로 계산할 수 있다.(계산 속도가 매우 빨라짐)

  • 보통 0을 추가해 길이를 맞추는 제로패딩 방식을 사용한다.

원 핫 인코딩(One-Hot Encoding)

  • 정수로 표현되었지만 실제로는 문자인 이 데이터를 기계가 인식할 수 있도록 바꿔주는 방법
  • 정수 인코딩을 했을 때 단어에 숫자가 부여되는데, 이러한 숫자는 대소관계를 가지므로 인코딩방법으로 적합하지 않다.
  • 원 핫 인코딩은 1차원 벡터의 형태로 인코딩하는 방식으로, 표현하고자 하는 단어의 자리는 1, 나머지는 0으로 채워넣은 벡터로 인코딩
  • 하지만 단어와 문장의 개수가 많아지면, 필요한 공간이 엄청나게 늘어나고 0의 개수가 많아지므로 희소 데이터(sparse data)가 된다.

백오브 워즈(Bag of Words, BoW)

  • bag은 원소의 순서를 고려하지 않고 중복 원소를 허용하는 집합을 의미한다.
  • 단어의 등장 순서를 고려하지 않고, 문서 내 단어의 등장 빈도를 고려한다.

문서 단어 행렬(Document Term Matrix, DTM)

  • 각 문서에 대한 BoW 표현 방법을 그대로 갖고 와서, 서로 다른 문서들의 BoW들을 결합한 표현방법
  • 원 핫 인코딩과 마찬가지로 공간적 낭비를 일으킬 수 있다.

TF-IDF

  • 단어의 빈도(TF, term frequency)와 역 문서 빈도(Inverse Document Frequency)를 사용하여 DTM 내의 각 단어들 마다 중요한 정도를 가중치로 주는 방법이다.
  • TF, IDF을 곱한 값으로 점수가 높을수록 해당 문서에서만 자주 등장하는 단어이다.
  • tf(d, t) : 단어의 빈도, DTM에서 각 단어들이 가진 값
  • df(t) : 특정 단어 t가 등장한 문서의 수, 문서에서 몇번 등장했는지는 고려하지 않는다.
  • idf(d, t) = log(\frac{n}{1 + df(t)})
  • idf(d, t) = log(n / (1 + df(t)))
    • log 사용 이유 : n이 커질수록 IDF 값이 급격하게 증가하는 것 방지
    • 1 더한 이유 : 0되는 것 방지

파이썬 활용

불용어 제거 및 빈도수 측정

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

text = """
	분석하고자 하는 문장 입력
"""
sent_text = sent_tokenize(text) # text를 문장 토큰화
nltk.download('stopwords') # 불용어 다운로드

vocabulary = {}
sentences = []
stop_words = stopwords.words('english')

for sent in sent_text :
    sentence = word_tokenize(sent)
    result = []
    
    for word in sentence :
        word = word.lower()
        if (word not in stop_words) & (len(word) > 2) :  # 불용어가 아니거나 길이가 3 이상인 단어
            result.append(word)
            if word not in vocabulary :
                vocabulary[word] = 0 # key값을 word로 가지는 dictionary 생성
            vocabulary[word] += 1 # 등장횟수
            
	sentences.append(result)

2번 이상 등장한 단어 빈도수 측정, 정수값 부여

sorted_vocabulary = sorted(vocabulary.items(), key = lambda x : x[1], reverse = True) # lambda x : x[1] 은 value값을 의미

# 정수 임베딩
integer_embedding = {}
i = 0
for (word, frequency) in sorted_vocabulary :
    if frequency > 1 :
        i += 1
        integer_embedding[word] = 1
    
integer_embedding["oov"] = len(integer_embedding) + 1 # 상위 4개의 단어를 제외한 단어들

encoded = []
for s in sentences :
    temp = []
    for w in s :
        try : # integer_embedding의 key값은 monkey, banana, jungle, food 4가지만 있음
            temp.append(integer_embedding[w])
        except KeyError : # 4가지 이외의 경우(KeyError)의 경우 'oov'의 value값으로 할당
            temp.append(integer_embedding["oov"])
	encoded.append(temp)

Counter 활용

빈도수 측정

import numpy as np
from Collections import Counter

words = np.hstack(sentences) # hstack은 ndarray 형식의 배열 수평으로 결합할 때 사용하는 함수
# hstack은 행의 개수가 같고 열의 개수가 다른 두 행렬을 합칠 때 사용
# vstack은 열의 개수가 같고 행의 개수가 다른 두 행렬을 합칠 때 사용

vocabulary = Counter(words)

정수 인코딩

vocab_size = 4
common_vocabulary = vocabulary.most_common(vocab_size)

integer_embedding = {}
i = 0
for (Word, frequency) in common_vocabulary :
    i = i + 1
    integer_embedding[word] = i
    

NLTK Freqdict 활용

정수 인코딩

from nltk import FreqDist
vocabulary = FreqDist(np.hstack(sentences))

vocab_size = 4
common_vocabulary = vocabulary.most_common(vocab_size)

integer_embedding = {word[0] : index + 1 for index, word in enumerate(common_vocabulary)}

Tensorflow Keras 활용

빈도수를 기준으로 정수 부여

from tensorflow.keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer()
tokenizer.fit_on_texts(sentences)

tokenizer.word_counts

integer_encoding = tokenizer.texts_to_sequences(sentences)

Padding

파이썬 활용

max_len = max(len(encode) for encode in integer_encoding)

for encode in integer_encoding :
    while len(encode) < max_len :
        encode.append(0)
        
padding = np.array(integer_encoding)

keras 활용

from tensorflow.keras.preprocessing.sequence import pad_sequences

integer_encoding = tokenizer.texts_to_sequences(sentences)
padding = pad_sequences(integer_encoding) # 앞에서부터 제로패딩

padding = pad_sequences(integer_encoding, padding = 'post', maxlen = 6) # 뒤에서부터 패딩, 열의 개수 설정

padding = pad_sequences(integer_encoding, padding = 'post', value = -1) # 패딩값 변경

TF-IDF

import math
documents = [
    "배가 너무 너무 아프다",
    "배가 너무 고프다",
    "저기 저기 배가 지나간다",
    "비가 와서 다리가 아프다"
]

vocabulary = list(set(w for doc in documents for w in doc.split()))

num_documents = len(documents)

TF, IDF 계산하는 함수

def tf(t, d) :
    return d.count(t)

def idf(t) :
    df = 0
    for doc in documents :
        df += t in oc
	return math.log(num_documents / (1 + df))

def tfidf(t, d) :
    return tf(t, d) * idf(t)

계산하기

TF

import pandas as pd

result = []
for i in range(num_documents) :
    result.append([])
    d = documents[i]
    for j in range(len(vocabulary)) :
        t = vocabulary[j]
        result[-1].append(tf(t, d))
        
term_frequency = pd.DataFrame(result, columns = vocabulary)

IDF

result = []
for i in range(len(vocabulary)) :
    t = vocabulary[i]
    result.append(idf(t))
    
inverse_df = pd.DataFrame(result, index = vocabulary, columns = ["IDF"])

TF-IDF

result = []
for i in range(num_documents) :
    result.append([])
    d = documents[i]
    for j in range(len(vocabulary)) :
        t = vocabulary[i]
        result[-1].append(tfidf(t, d))

tf_idf = pd.DataFrame(result, columns = vocabulary)

댓글남기기