오늘은 자연어 처리 전 input data를 만들 때 필요한 패딩과 원-핫인코딩에 대해서 학습해보겠습니다.
패딩(Padding)
- 자연어 처리를 하다보면 각 문장(또는 문서)의 길이가 서로 다른 경우가 있는데 기계는 길이가 동일한 문서들을 하나의 행렬로 보고 한꺼번에 병렬로 처리함. 따라서, 길이가 다른 문장들을 동일하게 맞춰주는 작업이 필요함.
- 이때, 데이터에 특정 값을 채워서 데이터 크기를 조정하는 것을 패딩이라고 하며, 숫자 0을 사용하면 제로 패딩이라고 함.
- 아래는 길이가 다른 문장을 가장 길이가 긴 문장에 맞추어 0으로 제로 패딩한 예시임.
import numpy as np
from tensorflow.keras.preprocessing.text import Tokenizer
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']]
tokenizer=Tokenizer()
tokenizer.fit_on_texts(preprocessed_sentences) # 단어 빈도수가 높은 순으로 낮은 정수 인덱스 부여
encoded=tokenizer.texts_to_sequences(preprocessed_sentences)
print(encoded)
[[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]]
max_len=max(len(item) for item in encoded)
print('최대 길이:', max_len)
최대 길이: 7
for sentence in encoded:
while len(sentence) < max_len:
sentence.append(0)
padded_np = np.array(encoded)
padded_np
array([[ 1, 5, 0, 0, 0, 0, 0],
[ 1, 8, 5, 0, 0, 0, 0],
[ 1, 3, 5, 0, 0, 0, 0],
[ 9, 2, 0, 0, 0, 0, 0],
[ 2, 4, 3, 2, 0, 0, 0],
[ 3, 2, 0, 0, 0, 0, 0],
[ 1, 4, 6, 0, 0, 0, 0],
[ 1, 4, 6, 0, 0, 0, 0],
[ 1, 4, 2, 0, 0, 0, 0],
[ 7, 7, 3, 2, 10, 1, 11],
[ 1, 12, 3, 13, 0, 0, 0]])
- 위의 과정을 케라스에서는 pad_sequences()를 사용하여 좀 더 간단하게 할 수 있음.
encoded=tokenizer.texts_to_sequences(preprocessed_sentences)
print(encoded)
[[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]]
from tensorflow.keras.preprocessing.sequence import pad_sequences
padded=pad_sequences(encoded)
padded
array([[ 0, 0, 0, 0, 0, 1, 5],
[ 0, 0, 0, 0, 1, 8, 5],
[ 0, 0, 0, 0, 1, 3, 5],
[ 0, 0, 0, 0, 0, 9, 2],
[ 0, 0, 0, 2, 4, 3, 2],
[ 0, 0, 0, 0, 0, 3, 2],
[ 0, 0, 0, 0, 1, 4, 6],
[ 0, 0, 0, 0, 1, 4, 6],
[ 0, 0, 0, 0, 1, 4, 2],
[ 7, 7, 3, 2, 10, 1, 11],
[ 0, 0, 0, 1, 12, 3, 13]], dtype=int32)
- 위의 실행 결과에서 알 수 있듯이, pad_sequences는 문서의 앞에 0을 채우는데 뒤에 0을 채우고 싶으면 padding='post'를 추가해주면 됨.
padded=pad_sequences(encoded, padding='post')
padded
array([[ 1, 5, 0, 0, 0, 0, 0],
[ 1, 8, 5, 0, 0, 0, 0],
[ 1, 3, 5, 0, 0, 0, 0],
[ 9, 2, 0, 0, 0, 0, 0],
[ 2, 4, 3, 2, 0, 0, 0],
[ 3, 2, 0, 0, 0, 0, 0],
[ 1, 4, 6, 0, 0, 0, 0],
[ 1, 4, 6, 0, 0, 0, 0],
[ 1, 4, 2, 0, 0, 0, 0],
[ 7, 7, 3, 2, 10, 1, 11],
[ 1, 12, 3, 13, 0, 0, 0]], dtype=int32)
원-핫 인코딩(One-Hot Encoding)
- 원-핫 인코딩을 하기 위해서는 먼저 단어 집합에 고유한 정수를 부여하는 정수 인코딩을 진행할 필요가 있음. 그 이후에 표현하고 싶은 단어의 고유한 정수를 인덱스로 간주하고 해당 위치에 1을 부여하고, 다른 단어의 인덱스의 위치에는 0을 부여하면 됨.
from konlpy.tag import Okt
okt=Okt()
tokens=okt.morphs("나는 자연어 처리를 배운다")
print(tokens)
['나', '는', '자연어', '처리', '를', '배운다']
word_to_index={word:index for index, word in enumerate(tokens)}
print('단어집합:', word_to_index)
단어집합: {'나': 0, '는': 1, '자연어': 2, '처리': 3, '를': 4, '배운다': 5}
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("자연어", word_to_index)
[0, 0, 1, 0, 0, 0]
- 위와 같이 원-핫 인코딩을 위해 직접 코드를 작성할 수도 있지만 케라스의 to_categorical()을 이용하여 좀 더 간단하게 원-핫인코딩을 수행할 수 있음.
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.utils import to_categorical
text = "나랑 점심 먹으러 갈래 점심 메뉴는 햄버거 갈래 갈래 햄버거 최고야"
tokenizer = Tokenizer()
tokenizer.fit_on_texts([text])
print('단 어 집 합 :',tokenizer.word_index)
단 어 집 합 : {'갈래': 1, '점심': 2, '햄버거': 3, '나랑': 4, '먹으러': 5, '메뉴는': 6, '최고야': 7}
sub_text="점심 먹으러 갈래 메뉴는 햄버거 최고야"
encoded=tokenizer.texts_to_sequences([sub_text])[0]
print(encoded)
[2, 5, 1, 6, 3, 7]
one_hot=to_categorical(encoded)
print(one_hot)
[[0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0.]
[0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0.]
[0. 0. 0. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 1.]]
- 원-핫 인코딩의 경우 단어의 개수가 늘어날수록 벡터의 차원이 늘어나야 하므로 저장 공간 측면에서 매우 비효율적인 방법임.
- 또한, 단어들의 유사도를 표현하지 못한다는 단점이 있음.
출처: 유원준/안상준, 딥러닝을 이용한 자연어 처리 입문-1권, p95-p103.
'자연어 처리' 카테고리의 다른 글
[딥러닝을 이용한 자연어 처리 입문] 벡터의 유사도 (0) | 2023.04.06 |
---|---|
[딥러닝을 이용한 자연어 처리 입문] 카운트 기반의 언어 모델 (0) | 2023.03.20 |
[딥러닝을 이용한 자연어 처리 입문] 언어모델 (0) | 2023.03.04 |
[딥러닝을 이용한 자연어 처리 입문] 정규 표현식 (0) | 2023.02.25 |
[딥러닝을 이용한 자연어 처리 입문] 토큰화 및 전처리 (0) | 2023.02.19 |