워드 임베딩은 단어를 컴퓨터가 이해하고, 효율적으로 처리할 수 있도록 단어를 벡터화하는 기술
워드 임베딩은 단어의 의미를 잘 표현해야만 하며, 현재까지도 많은 표현 방법이 연구
워드 임베딩을 거쳐 잘 표현된 단어 벡터들은 계산이 가능하며, 모델 투입도 가능
인코딩(Encoding)
기계는 자연어(영어, 한국어 등)을 이해할 수 없음
데이터를 기계가 이해할 수 있도록 숫자 등으로 변환해주는 작업이 필요
이러한 작업을 인코딩이라고 함
텍스트 처리에서는 주로 정수 인코딩, 원 핫 인코딩을 사용
정수 인코딩
dictionary를 이용한 정수 인코딩
각 단어와 정수 인덱스를 연결하고, 토큰을 변환해주는 정수 인코딩
text = "평생 살 것처럼 꿈을 꾸어라. 그리고 내일 죽을 것처럼 오늘을 살아라."
tokens = [x for x in text.split(' ')]
unique = set(tokens) # 토큰이 중복되지 않도록
unique = list(unique)
token2idx = {}
for i in range(len(unique)):
token2idx[unique[i]] = i
encode = [token2idx[x]for x in tokens]
encode # [5, 9, 7, 6, 3, 8, 1, 4, 7, 0, 2]
keras를 이용한 정수 인코딩
정수 인코딩은 단어에 정수로 레이블을 부여
dictionary,nltk패키지를 이용한 방법들도 있지만,keras에서는 텍스트 처리에 필요한 도구들을 지원
해당 도구는 자동으로 단어 빈도가 높은 단어의 인덱스는 낮게끔 설정
from tensorflow.keras.preprocessing.text import Tokenizer
text = "평생 살 것처럼 꿈을 꾸어라. 그리고 내일 죽을 것처럼 오늘을 살아라."
t = Tokenizer()
t.fit_on_texts([text]) # Tokenizer().fit_on_texts()에는 텍스트로 이루어진 리스트를 넣어야 함
print(t.word_index) # 딕셔너리로 표현됨 : {'것처럼': 1, '평생': 2, '살': 3, '꿈을': 4, '꾸어라': 5, '그리고': 6, '내일': 7, '죽을': 8, '오늘을': 9, '살아라': 10}
encoded = t.texts_to_sequences([text])[0]
print(encoded) # [2, 3, 1, 4, 5, 6, 7, 8, 1, 9, 10]
원 핫 인코딩(One-Hot Encoding)
정수 인코딩보다는 원 핫 인코딩을 더 자주 씀.
조건문과 반복문을 이용한 원 핫 인코딩
원 핫 인코딩은 정수 인코딩한 결과를 벡터로 변환한 인코딩
원 핫 인코딩은 전체 단어 개수 만큼의 길이를 가진 배열에 해당 정수를 가진 위치는 1, 나머지는 0을 가진 벡터로 변환
import numpy as np
one_hot = []
for i in range(len(encoded)):
temp = []
for j in range(max(encoded)):
if j == (encoded[i] - 1): # encoded의 값은 1부터 시작. for문은 0부터 시작
temp.append(1)
else :
temp.append(0)
one_hot.append(temp)
np.array(one_hot)
keras를 이용한 원 핫 인코딩
keras에서는 정수 인코딩을 원 핫 인코딩을 간단하게 변환해주는to_categorical()함수를 제공
from tensorflow.keras.utils import to_categorical
one_hot = to_categorical(encoded)
one_hot
from tensorflow.keras.datasets import imdb
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Dense, Flatten
print(x_train[0]) # 이렇게 임베딩된 데이터는
print(y_train[0]) # 긍정이당!
for i in range(10):
if y_train[i] == 0:
label = '부정'
else:
label = '긍정'
print('{}\n{}'.format(x_train[i], label)) # 첫 10개 리뷰에 대해서, 임베딩된 정수 리스트와 함께 긍정인지 부정인지 출력
4. 데이터 전처리
모든 데이터를 같은 길이로 맞추기
pad_sequence()
데이터가 maxlen보다 길면 데이터를 자름
데이터가 길면padding설정
pre: 데이터 앞에 0으로 채움
post: 데이터 뒤에 0으로 채움
모든 데이터(문장 하나하나)가 같은 길이로 맞추어야 Embedding 레이어를 사용할 수 있음
from tensorflow.keras.preprocessing.sequence import pad_sequences
max_len = 100
pad_x_train = pad_sequences(x_train, maxlen=max_len, padding='pre')
pad_x_test = pad_sequences(x_test, maxlen=max_len, padding='pre')
# 전처리 확인하기
print(len(x_train[5])) # 43
print(len(pad_x_train[5])) # 100
# 길이가 잘 맞춰진 것을 알 수 있음 (나머지 57개는 맨 앞에 0 57개로 채워짐)
print(len(x_train[1])) # 189
print(len(pad_x_train[1])) # 100
# 이 경우에는 데이터가 잘림
5. 모델 구성
model = Sequential()
model.add(Embedding(input_dim=num_words, output_dim=32,input_length=max_len))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.summary()
6. 모델 컴파일 및 학습
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['acc'])
history=model.fit(pad_x_train, y_train,
epochs=10,
batch_size=32,
validation_split=0.2) # 오버피팅됨. 모델 안에 일반화를 시킬 수 있는 장치가 없음..ㅜ
import re
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
nltk.download('stopwords')
nltk.download('punkt')
def clean_text(d):
pattern = r'[^a-zA-Z\s]'
text = re.sub(pattern, '', d)
return text
# 댓글 참고해서 함수 수정
def clean_stopword(d):
stop_words = stopwords.words('english')
return ' '.join(w.lower() for w in d.split() if w.lower() not in stop_words and len(w)>3)
def tokenize(d):
return word_tokenize(d)
import pandas as pd
news_df = pd.DataFrame({'article':documents})
len(news_df) # 11314
news_df['article'] = news_df['article'].apply(clean_text)
# news_df['article']
news_df['article'] = news_df['article'].apply(clean_stopword)
# news_df['article']
tokenized_news = news_df['article'].apply(tokenize)
tokenized_news = tokenized_news.to_list()
import numpy as np
drop_news = [index for index, sentence in enumerate(tokenized_news) if len(sentence) <= 1] # 불필요한 데이터 (제거 대상)
news_texts = np.delete(tokenized_news, drop_news, axis = 0)
print(len(news_texts)) # 10939
Gensim을 이용한 Word2Vec
1. CBOW
from gensim.models import Word2Vec
# gensim 버전이 다른 것인지 유튜브와는 달리 size 대신 vector_size 사용함
model = Word2Vec(sentences=news_texts,
window=4, # 고려할 앞 뒤 폭
vector_size=100, # 벡터 크기
min_count=5, # 사용할 단어의 최소 빈도 (5회 이하 단어 무시)
workers=4, # 동시에 처리할 작업의 수
sg=0) # 0 : cbow, 1 : skip-gram
model.save('word2vec.model') # 저장하기
model = Word2Vec.load('word2vec.model') # 불러오기
# skip-gram
from gensim.models import Word2Vec
# gensim 버전이 다른 것인지 유튜브와는 달리 size 대신 vector_size 사용함
model = Word2Vec(sentences=news_texts,
window=4, # 고려할 앞 뒤 폭
vector_size=100, # 벡터 크기
min_count=5, # 사용할 단어의 최소 빈도 (5회 이하 단어 무시)
workers=4, # 동시에 처리할 작업의 수
sg=1) # 0 : cbow, 1 : skip-gram
model.save('word2vec.model2') # 저장하기
model = Word2Vec.load('word2vec.model2') # 불러오기
댓글