본문 바로가기
AI

자연어처리 : 텍스트 처리 : 정수 인코딩 (Integer Encoding)

by 월곡동로봇팔 2020. 3. 4.

정의

  • 컴퓨터는 text보다는 number를 더 잘 처리한다. 따라서 text를 number로 바꾸는 작업을 하기도 한다.
  • 단어를 정수에 mapping시키는 전처리 작업을 해야한다.
  • index 부여방법은 빈도수가 높은 단어들만 사용하기 위해서 단어에 대한 빈도수를 기준으로 정렬한 뒤 부여한다.
  • text를 숫자로 바꾸는 작업 전에는 전처리 단계가 모두 끝나있어야 한다.

1. 정수 인코딩 (Integer Encoding)

1) Dictionary 이용

  1. dictionary 사용해서 문장 토큰화 및 정제작업을 거친 단어 토큰화 진행
  2. dict에는 중복을 제거한 단어와 각 단어에 대한 빈도수가 기록
  3. 빈도수 높은 단어 -> 낮은 index 부여
  4. 빈도수 낮은 단어들을 Out-Of-Vocabulary, OOV 로 다시 mapping

위 과정이 너무 귀찮기 때문에 counter, FreqDist, Enumerate 를 사용하자.

 

2) Counter 사용

from collections import Counter

print(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']]
"""

words=sum(sentences, [])
# 위 작업은 words = np.hstack(sentences)로도 수행 가능.
print(words)

"""
['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']
"""
vocab=Counter(words) # 파이썬의 Counter 모듈을 이용하면 단어의 모든 빈도를 쉽게 계산할 수 있습니다.
print(vocab)
Counter({'barber': 8, 'secret': 6, 'huge': 5, 'kept': 4, 'person': 3, 'word': 2, 
		'keeping': 2, 'good': 1, 'knew': 1, 'driving': 1, 'crazy': 1, 'went': 1, 'mountain': 1})

Counter 모듈을 이용하면 collection을 보다 쉽게 가능하다.

 

print(vocab["barber"]) # 'barber'라는 단어의 빈도수 출력
8

# most_common()는 상위 빈도수를 가진 주어진 수의 단어만을 리턴합니다. 
# 이를 사용하여 등장 빈도수가 높은 단어들을 원하는 개수만큼만 얻을 수 있습니다. 
# 등장 빈도수 상위 5개의 단어만 단어 집합으로 저장해봅시다.

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

#이제 높은 빈도수를 가진 단어일수록 낮은 정수 인덱스를 부여합니다.
word_to_index={}
i=0
for (word, frequency) in vocab :
    i=i+1
    word_to_index[word]=i
print(word_to_index)
{'barber': 1, 'secret': 2, 'huge': 3, 'kept': 4, 'person': 5}

 

3) NLTK의 FreqDist + Enumerate사용하기

2020/02/24 - [machine_learning/natural language] - 자연어처리 : NLTK

 

자연어처리 : NLTK

NLTK (Natural Language ToolKit) NLTK 란? nltk는 파이썬 자연어 처리 패키지로 Classfication (분류) Tokenization (단어를 쪼개다) Stemming(형태소 분석) tagging (품사를 달다) parsing (어구를 나누다) sema..

mambo-coding-note.tistory.com

FreqDist 는 안에 list를 넣으면 알아서 count를 다 해준다.

from nltk import FreqDist
import numpy as np

# np.hstack으로 문장 구분을 제거하여 입력으로 사용 . 
# ex) ['barber', 'person', 'barber', 'good' ... 중략 ...

vocab = FreqDist(np.hstack(sentences))

print(vocab["barber"])

"""
8
"""
from nltk import FreqDist
>>> vocab = FreqDist(b)
>>> vocab
FreqDist({'they': 1, 't': 1, "isn't": 1, 'by': 1, 'weren': 1, 'after': 1, "mightn't": 1, 'just': 1, 'was': 1, 'any': 1, ...})
>>> type(vocab)
<class 'nltk.probability.FreqDist'>
>>> vocab.most_common(5)
[('they', 1), ('t', 1), ("isn't", 1), ('by', 1), ('weren', 1)]

FreqDist의 객체인 vocab는 dict 구조를 가지지만, most_common을 하면 list가 출력된다.

word_to_index={word[0] : index+1 for index, word in enumerate(vocab)}
print(word_to_index)

"""
{'barber': 1, 'secret': 2, 'huge': 3, 'kept': 4, 'person': 5}
"""

2. keras의 텍스트 전처리

fit_on_texts

from tensorflow.keras.preprocessing.text import Tokenizer
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']]
            
# 단어 토큰화까지 수행된 앞서 사용한 텍스트 데이터와 동일한 데이터를 사용합니다.

tokenizer = Tokenizer()
tokenizer.fit_on_texts(sentences) 
# fit_on_texts()안에 코퍼스를 입력으로 하면 빈도수를 기준으로 단어 집합을 생성한다.

word_index

print(tokenizer.word_index)

{'barber': 1, 'secret': 2, 'huge': 3, 'kept': 4, 'person': 5, 'word': 6, 
 'keeping': 7, 'good': 8, 'knew': 9, 'driving': 10, 'crazy': 11, 'went': 12, 
 'mountain': 13}

각 단어가 빈도수 높은 순으로 indexing이 되어있다.

word_counts

print(tokenizer.word_counts)

OrderedDict([('barber', 8), ('person', 3), ('good', 1), ('huge', 5), ('knew', 1), 
			('secret', 6), ('kept', 4), ('word', 2), ('keeping', 2), 
            ('driving', 1), ('crazy', 1), ('went', 1), ('mountain', 1)])

texts_to_sequences (festival에서 썼던 method)

print(tokenizer.texts_to_sequences(sentences))

"""
[[1, 5], [1, 8, 5], [1, 3, 5], [9, 2], [2, 4, 3, 2], [3, 2], 
 [1, 4, 6], [1, 4, 6], [1, 4, 2], [7, 7, 3, 2, 10, 1, 11], [1, 12, 3, 13]]
"""

texts_to_sequences method는 단어들은 index로 mapping한다. (정수로 encoding)

most_common과 같은 효과 : Tokenizer(number)

vocab_size=5
tokenizer = Tokenizer(num_words=vocab_size+1) # 상위 5개 단어만 사용
tokenizer.fit_on_texts(sentences)

실질적으로 숫자 0에 지정된 단어가 존재하지 않는데도 케라스 토크나이저가 숫자 0까지 단어 집합의 크기로 산정하는 이유는 자연어 처리에서 패딩(padding)이라는 작업 때문입니다. 이에 대해서는 뒤에 다루게 되므로 여기서는 케라스 토크나이저를 사용할 때는 숫자 0도 단어 집합의 크기로 고려해야한다고만 이해합시다.

 

word_counts, word_index를 출력해도 같은 결과값이 나오지만,

texts_to_sequences method를 할 때, 적용이 된다.

print(tokenizer.texts_to_sequences(sentences))

"""
[[1, 5], [1, 5], [1, 3, 5], [2], 
[2, 4, 3, 2], [3, 2], [1, 4], [1, 4], [1, 4, 2], [3, 2, 1], [1, 3]]
"""

댓글