자연어처리
(5) 자연어처리_ 워드 임베딩 시각화
빠스무
2023. 7. 30. 00:19
728x90
#표에 한글을 쓰기위해 폰트 다운로드
!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf
1. 네이버 영화 리뷰 데이터셋
- 총 200,000개의 리뷰로 구성된 데이터로, 영화 리뷰를 긍/부정으로 분류하기 위해 만들어진 데이터셋
- 리뷰가 긍정인 경우 1, 부정인 경우 0으로 표시한 레이블로 구성되어 있음
import urllib.request
import pandas as pd
urllib.request.urlretrieve('https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt', filename='ratings_train.txt')
urllib.request.urlretrieve('https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt', filename='ratings_test.txt')
train_dataset = pd.read_table('ratings_test.txt')
train_dataset
2. 데이터 전처리
# 결측치 확인하고 결측치를 제거
train_dataset.replace('', float('NaN'), inplace=True)
print(train_dataset.isnull().values.any())
train_dataset = train_dataset.dropna().reset_index(drop=True)
print(f'필터링된 데이터셋 총 개수: {len(train_dataset)}')
# 열을 기준으로 중복 데이터를 제거
train_dataset = train_dataset.drop_duplicates(['document']).reset_index(drop=True)
train_dataset
# 한글이 아닌 문자를 포함하는 데이터 제거(ㅋㅋㅋ 제거하지 않음)
train_dataset['document'] = train_dataset['document'].str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣]', ' ')
# train_dataset['document'] = train_dataset['document'].str.replace(pat=r'[^\w]', repl=r' ', regex=True)
# train_dataset['document'] = train_dataset['document'].str.replace(pat=r'[a-zA-Z]', repl=r' ', regex=True)
train_dataset['document']
# 너무 짧은 단어를 제거(단어의 길이가 1이하)
train_dataset['document'] = train_dataset['document'].apply(lambda x: ' '.join([token for token in x.split() if len(token) > 1]))
train_dataset
# 전체 길이가 100 이하이거나 전체 단어 개수가 5개 이하인 데이터를 제거
train_dataset = train_dataset[train_dataset.document.apply(lambda x: len(str(x)) > 100 and len(str(x).split()) > 5)].reset_index(drop=True)
train_dataset
!pip install konlpy
from konlpy.tag import Okt
# 불용어 정의
stopwords = ['의', '가', '이', '은', '들', '는', '좀', '잘', '걍', '과', '도', '를', '으로', '자', '에', '와', '한', '하다']
train_dataset = list(train_dataset['document'])
# train_dataset
okt = Okt()
tokenized_data = []
for sentence in train_dataset:
tokenized_sentence = okt.morphs(sentence, stem = True)
stopwords_removed_sentence = [word for word in tokenized_sentence if not word in stopwords]
tokenized_data.append(stopwords_removed_sentence)
tokenized_data[0]
# matplotlib hist 함수로 length of smaples 와 number of samples를 표현
# 리뷰의 최대 길이와 평균길이를 출력
import matplotlib.pyplot as plt
import numpy as np
# Step 2: 데이터 준비
sample_lengths = [len(sample) for sample in tokenized_data]
max_length = max(sample_lengths)
average_length = sum(sample_lengths) / len(sample_lengths)
# Step 3: 히스토그램 그리기
plt.hist(sample_lengths, bins='auto')
plt.xlabel('샘플의 길이')
plt.ylabel('샘플의 개수')
plt.title('샘플 길이 분포')
plt.show()
# Step 4: 최대 길이와 평균 길이 출력하기
print('최대 길이:', max_length)
print('평균 길이:', average_length)
3. 워드 임베딩 구축
from gensim.models import Word2Vec
embedding_dim = 100
# sg: 0(CBOW), 1(Skip-gram)
model = Word2Vec(
sentences = tokenized_data,
vector_size = embedding_dim,
window = 5,
min_count = 5,
workers = 4,
sg = 0
)
# 임베딩 행렬의 크기
# 단어 사전에는 총 12381개의 단어가 존재하고, 각각의 단어는 미리 설정한 embedding_dim = 100 차원으로 구성되어있음\
model.wv.vectors.shape
word_vectors = model.wv
vocabs = list(word_vectors.index_to_key)
vocabs[:20]
for sim_word in model.wv.most_similar('좋다'):
print(sim_word)
model.wv.similarity('좋다','괜찮다')
4. 워드 임베딩 시각화
import matplotlib.font_manager
font_list = matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
[matplotlib.font_manager.FontProperties(fname=font).get_name() for font in font_list if 'Nanum' in font]
plt.rc('font',family = 'NanumBarunGothic')
word_vector_list = [word_vectors[word] for word in vocabs]
word_vector_list[0]
# PCA가 자주 이용되는 차원 축소 방식이긴 하지만 군집의 변별력을 해친다는 단점이 있음
#PCA를 개선한 방법이 t-SNE 차원 축소 방식
from sklearn.manifold import TSNE
tsne = TSNE(learning_rate = 100)
transformed = tsne.fit_transform(np.array(word_vector_list))
x_axis_tsne = transformed[:,0]
y_axis_tsne = transformed[:,1]
def plot_tsne_graph(vocabs, x_asix, y_asix):
plt.figure(figsize=(30, 30))
plt.scatter(x_asix, y_asix, marker = 'o')
for i, v in enumerate(vocabs):
plt.annotate(v, xy=(x_asix[i], y_asix[i]))
plot_tsne_graph(vocabs, x_axis_tsne, y_axis_tsne)
5.TSNE 고도화
- Python에서 제공하는 interactive visualization library인 bokey를 사용하여 시각화 고도화
import pickle
tsne_df = pd.DataFrame(transformed, columns = ['x_coord', 'y_coord'])
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import HoverTool, ColumnDataSource, value
def plot_tsne_graph(vocabs, x_asix, y_asix):
plt.figure(figsize=(30, 30))
plt.scatter(x_asix, y_asix, marker = 'o')
for i, v in enumerate(vocabs):
plt.annotate(v, xy=(x_asix[i], y_asix[i]))
output_notebook()
# prepare the data in a form suitable for bokeh.
plot_data = ColumnDataSource(tsne_df)
# create the plot and configure it
tsne_plot = figure(title='t-SNE Word Embeddings',
plot_width = 800,
plot_height = 800,
active_scroll='wheel_zoom'
)
# add a hover tool to display words on roll-over
tsne_plot.add_tools( HoverTool(tooltips = '@word') )
tsne_plot.circle(
'x_coord', 'y_coord', source=plot_data,
color='red', line_alpha=0.2, fill_alpha=0.1,
size=10, hover_line_color='orange'
)
# adjust visual elements of the plot
tsne_plot.xaxis.visible = False
tsne_plot.yaxis.visible = False
tsne_plot.grid.grid_line_color = None
tsne_plot.outline_line_color = None
# show time!
show(tsne_plot);
from gensim.models import KeyedVectors
model.wv.save_word2vec_format('samle_word2vec_embedding')
!python -m gensim.scripts.word2vec2tensor --input sample_word2vec_embedding --output sample_word2vec_embedding