[모두의 딥러닝] 23. 텍스트 전처리 - 원-핫 인코딩(one-hot encoding), 단어 임베딩(word embedding), 긍정 부정 예측

원-핫 인코딩(one-hot encoding)

- 단어 또는 문장을 이진 벡터로 변환하여 각 단어 또는 문장 요소의 존재 여부를 표현

- 각 단어를 모두 0으로 바꾸고 원하는 단어만 1로 바꾸어 주는 것

나는 = [ 0 1 0 0 0 0 0 0 ]
그대만큼 = [ 0 0 1 0 0 0 0 0 ]
사랑스러운 = [ 0 0 0 1 0 0 0 0 ]
사람을 = [ 0 0 0 0 1 0 0 0 ]
본 = [ 0 0 0 0 0 1 0 0 ]
적이 = [ 0 0 0 0 0 0 1 0 ]
없다 =[ 0 0 0 0 0 0 0 1 ] 

※ 맨 첫 번째는 0 인덱스 자리

 

 

1. 토큰화 및 인덱스 값 출력

text = '나는 그대만큼 사랑스러운 사람을 본 적이 없다'
token = Tokenizer()
token.fit_on_texts([text])
print(token.word_index)
{'나는': 1, '그대만큼': 2, '사랑스러운': 3, '사람을': 4, '본': 5, '적이': 6, '없다': 7}

 

 

2. 토큰 인덱스 배열 생성

  • texts_to_sequences()

: 텍스트를 단어 단위로 분리하고, 각 단어를 해당하는 정수 인덱스로 변환하여 배열 생성

: Tokenizer에 존재

x = token.texts_to_sequences([text])
print(x)
[[1, 2, 3, 4, 5, 6, 7]]

 

 

3. 원-핫 인코딩

- 배열 맨 앞에 0이 추가되므로 단어 수보다 1이 더 많게 인덱스 숫자 잡아줘야 함

 

 

  • to_categorical()

: 정수로 인덱스된 배열을 0과 1로만 이루어진 배열로 바꾸어 줌

: keras에 존재

from tensorflow.keras.utils import to_categorical

#인덱스 수에 하나를 추가해서 원-핫 인코딩 배열 만들기
word_size = len(token.word_index) + 1
x = to_categorical(x, num_classes=word_size)
print(x)
[[[0. 1. 0. 0. 0. 0. 0. 0.]
  [0. 0. 1. 0. 0. 0. 0. 0.]
  [0. 0. 0. 1. 0. 0. 0. 0.]
  [0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 1. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0.]
  [0. 0. 0. 0. 0. 0. 0. 1.]]]

 

 

 

단어 임베딩(word embedding)

- 단어들 간의 의미적 유사성과 관계를 반영하도록 단어를 저차원의 밀집 벡터로 매핑

- 차원이 매우 크고, 단어 간의 의미적인 유사성을 고려하지 않은 원-핫 인코딩의 문제점 해결

원-핫 인코딩
단어 임베딩

 

 

  • Embedding(input_dim, output_dim, input_length=n)

: 단어를 밀집된 벡터로 표현

: keras에 존재

- input_dim : 입력될 총 단어 수

- output_dim : 임베딩 후 출력되는 벡터 크기

- input_length : 입력되는 배열의 길이

from tensorflow.keras.layers import Embedding

model = Sequential()
model.add(Embedding(16, 4, input_length=2))

 

 

 

긍정 부정 예측 코드

- 영화 리뷰를 딥러닝 모델로 학습해서 각 리뷰가 긍정적인지 부정적인지 예측

 

 

1. 리뷰 클래스 지정

from numpy import array

# 텍스트 리뷰 자료 지정
docs = ["너무 재밌네요","최고예요","참 잘 만든 영화예요","추천하고 싶은 영화입니다","한번 더 보고싶네요","글쎄요","별로예요","생각보다 지루하네요","연기가 어색해요","재미없어요"]

# 긍정 리뷰는 1, 부정 리뷰는 0으로 클래스 지정
classes = array([1,1,1,1,1,0,0,0,0,0])

 

 

2. 토큰화

token = Tokenizer()
token.fit_on_texts(docs)
print(token.word_index)
{'너무': 1, '재밌네요': 2, '최고예요': 3, '참': 4, '잘': 5, '만든': 6, '영화예요': 7, '추천하고': 8,
'싶은': 9, '영화입니다': 10, '한번': 11, '더': 12, '보고': 13, '싶네요': 14, '글쎄요': 15, 
'별로예요': 16, '생각보다': 17, '지루하네요': 18, '연기가': 19, '어색해요': 20, '재미없어요': 21}

 

 

3. 토큰 인덱스 배열 생성

x = token.texts_to_sequences(docs)
print("리뷰 텍스트, 토큰화 결과:\n", x)
리뷰 텍스트, 토큰화 결과:
 [[1, 2], [3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13, 14], [15], [16], [17, 18], [19, 20], [21]]

 

 

4. 패딩(padding)

- 학습 데이터의 길이를 똑같이 맞추어 주는 작업

 

  • pad_sequences()

: 원하는 길이보다 짧은 부분은 숫자 0을 넣어서 채워 주고, 긴 데이터는 잘라서 같은 길이로 맞춤

: keras에 존재

from tensorflow.keras.preprocessing.sequence import pad_sequences

# 패딩. 서로 다른 길이의 데이터를 4로 맞추어 줌
padded_x = pad_sequences(x, 4)
print("패딩 결과:\n", padded_x)
패딩 결과:
 [[ 0  0  1  2]
 [ 0  0  0  3]
 [ 4  5  6  7]
 [ 0  8  9 10]
 [11 12 13 14]
 [ 0  0  0 15]
 [ 0  0  0 16]
 [ 0  0 17 18]
 [ 0  0 19 20]
 [ 0  0  0 21]]

 

 

5. 모델 설정 - 단어 임베딩 포함

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Flatten,Embedding

# 단어 임베딩 함수의 입력 인덱스 수
word_size = len(token.word_index) + 1

model = Sequential()
model.add(Embedding(word_size, 8, input_length=4))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.summary()

 

 

6. 모델 실행

model.compile(optimizer='adam',loss='binary_crossentropy', metrics=['accuracy'])
model.fit(padded_x, classes, epochs=20)
print("\nAccuracy : %.4f" % (model.evaluate(padded_x, classes)[1]))

 

 

 

'모두의 딥러닝 개정 3판'의 내용과 https://github.com/taehojo/deeplearning의 코드 참고