본문 바로가기
AI

워드 임베딩 시각화

by 코낄2 2024. 1. 31.

 

  • # 폰트 다운로드 !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')

2. 데이터 전처리

# 결측치 확인하고 결측치 제거
# train_dataset = train_dataset.dropna().reset_index(drop=True)
# print(f'필터링된 데이터셋 총 개수: {len(train_dataset)}')

train_dataset.replace('', float('NaN'), inplace=True)
train_dataset.isnull().values.any()

train_dataset=train_dataset.dropna().reset_index(drop=True)
len(train_dataset)
  • 열을 기준으로 중복 데이터를 제거
train_dataset = train_dataset.drop_duplicates(['document']).reset_index(drop=True)
  • 한글이 아닌 문자를 포함하는 데이터를 제거(단, ㅋㅋㅋ 제거하지 않음)
train_dataset['document'] = train_dataset['document'].str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣]', ' ')
  • 너무 짧은 단어를 제거(단어의 길이가 한글자인 단어 제거)
train_dataset['document'] = train_dataset['document'].apply(lambda x: ' '.join([token for token in x.split() if len(token)>1]))
  • 전체 길이가 10자 이하이거나 전체 단어의 개수가 5개 이하인 데이터를 제거
train_dataset = train_dataset[train_dataset.document.apply(lambda x: len(str(x)) > 10 and len(str(x).split()) > 5)].reset_index(drop=True)

!pip install konlpy

- Okt : 한국어 텍스트를 형태소 분석하는 데 사용되는 KoNLPy(코엔엘파이) 라이브러리의 한 형태소 분석기

from konlpy.tag import Okt

okt = Okt()
# 불용어 정의
stop_word = "아 휴 아이구 아이쿠 아이고 어 나 우리 저희 따라 의해 을 를 에 의 가 으로 로 에게 뿐이다 의거하여 근거하여 입각하여 기준으로 예하면 예를 들면 예를 들자면 저 소인 소생 저희 지말고 하지마 하지마라 다른 물론 또한 그리고 비길수 없다 해서는 안된다 뿐만 아니라 만이 아니다 만은 아니다 막론하고 관계없이 그치지 않다 그러나 그런데 하지만 든간에 논하지 않다 따지지 않다 설사 비록 더라도 아니면 만 못하다 하는 편이 낫다 불문하고 향하여 향해서 향하다 쪽으로 틈타 이용하여 타다 오르다 제외하고 이 외에 이 밖에 하여야 비로소 한다면 몰라도 외에도 이곳 여기 부터 기점으로 따라서 할 생각이다 하려고하다 이리하여 그리하여 그렇게 함으로써 하지만 일때 할때 앞에서 중에서 보는데서 으로써 로써 까지 해야한다 일것이다 반드시 할줄알다 할수있다 할수있어 임에 틀림없다 한다면 등 등등 제 겨우 단지 다만 할뿐 딩동 댕그 대해서 대하여 대하면 훨씬 얼마나 얼마만큼 얼마큼"
stop_word = stop_word.split(' ')
train_dataset = list(train_dataset['document'])

# 모든 형태소를 tokenized_data에 저장
# 단 원형으로 표기
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 stop_word]
    tokenized_data.append(stopwords_removed_sentence)
    
tokenized_data[0]
// ['뭐', '야', '평점', '들', '은', '나쁘다', '짜다', '리', '는', '더', '더욱']

3. 워드 임베딩 구축

from gensim.models import Word2Vec
embedding_dim = 100

# sg: 0(CBOW), 1(Skip-gram)
# workers: 컴퓨터 코어수를 몇개 쓸건지. 작업관리자- 성능에서 확인. 코어수를 넘어가면 안되고, 또 다른 작업도 있으니 다 쓰면 안됨
model = Word2Vec(
    sentences = tokenized_data,
    vector_size = embedding_dim,
    window = 5,
    min_count = 5,
    workers=4,
    sg = 0
)

window = 5: 주어진 단어 주변에 고려할 문맥의 최대 범위를 설정

min_count = 5: 학습에 사용할 단어의 최소 등장 빈도를 설정. 빈도가 너무 낮은 단어들을 제거하여 모델의 품질을 향상

workers=4: 학습에 사용되는 CPU 코어의 수를 설정. 병렬 처리를 통해 학습 속도향상

sg = 0: Skip-gram 모델을 사용할지(1) 또는 CBOW 모델을 사용할지(0)를 결정

# 임베딩 행렬의 크기
model.wv.vectors.shape // (6298, 100)

word_vectors = model.wv
vocabs = list(word_vectors.index_to_key)
vocabs[:20]
// ['영화', '하다', '보다', '도', '들', '는', '은', '있다', '이다', '좋다', '너무', '한', 
'정말', '같다', '적', '되다', '진짜', '에서', '과', '연기']
  1. word_vectors = model.wv: 학습된 Word2Vec 모델에서 단어 벡터를 추출합니다. wv는 Word Vectors의 약자로, 학습된 Word2Vec 모델 객체(model)에서 단어 벡터를 추출하는데 사용되는 속성입니다.
  2. vocabs = list(word_vectors.index_to_key): 추출된 단어 벡터에서 어휘를 추출합니다. index_to_key는 단어의 인덱스를 키로, 해당 단어를 값으로 하는 딕셔너리입니다. 이 코드에서는 이 딕셔너리를 리스트로 변환하여 어휘를 얻습니다.

유사 단어 추출

for sim_word in model.wv.most_similar('영화'):
    print(sim_word)
('명작', 0.8060880899429321)
('영화로', 0.7764174938201904)
('애니', 0.767850935459137)
('잘만', 0.752373218536377)
('과언', 0.7495825290679932)
('애니메이션', 0.7388995885848999)
('이렇다', 0.7368715405464172)
('공포영화', 0.7339376211166382)
('큐브릭', 0.7336830496788025)
('판타지영화', 0.7268518805503845)

for sim_word in model.wv.most_similar('좋다'):
    print(sim_word)
('예쁘다', 0.888930082321167)
('멋지다', 0.886707067489624)
('호랑이', 0.8734232187271118)
('아쉽다', 0.8654603362083435)
('색감', 0.857334315776825)
('귀엽다', 0.8490276336669922)
('괜찮다', 0.847762942314148)
('음악', 0.8393566012382507)
('노래', 0.835949182510376)
('훌륭하다', 0.8356144428253174)
# 두 단어의 유사성을 출력
model.wv.similarity('좋다', '신선하다')
// 0.8085689

4. 워드 임베딩 시각화

import matplotlib.font_manager

font_list = matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
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
import numpy as np
tsne = TSNE(init='random')
transformed = tsne.fit_transform(np.array(word_vector_list))

x_axis_tsne = transformed[:, 0]
y_axis_tsne = transformed[:, 1]

print(x_axis_tsne)
// [-26.300535  -46.93301   -49.98806   ...  -1.3044238 -31.668127  -45.12195  ]
print(y_axis_tsne)
// [ 15.158021  33.612858  18.691015 ... -40.259975 -47.87023  -39.224438]
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)

 

'AI' 카테고리의 다른 글

KLUE  (0) 2024.02.02
[논문 리뷰]attention 매커니즘  (0) 2024.01.31
임베딩  (0) 2024.01.24
데이터 전처리 실습  (0) 2024.01.19
자연어 처리 진행 순서  (0) 2024.01.19