수달이네 기술 블로그

3. NSMC를 활용한 단어 분류 본문

AI공부/자연어처리

3. NSMC를 활용한 단어 분류

슬픈 수달이 2026. 2. 20. 18:01

NSMC(Naver Sentiment Movie Corpus)

네이버 영화 리뷰를 기반으로 구축된 한국어 감성 분석 데이터셋

  • 200,000개의 리뷰
  • 긍정(1), 부정 (0) 레이블로 분류
  • 위 데이터셋을 분석해서 자연어를 분석할 것이다.
!pip install konlpy # 형태소분석기(이 안의 기능을 사용할 것)
!pip install mecab-python # 형태소 분석기 (형태소분석기는 이걸 사용)
!bash <(curl -s <https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh>)
  • 형태소분석기: 토크나이징 시킬때 형태소 별로 분석해서 나눔

사전 import

import urllib.request  
from konlpy.tag import Mecab
from gensim.models.word2vec import Word2Vec
import pandas as pd
import matplotlib.pyplot as plt

데이터 가져오기

urllib.request.urlretrieve("<https://raw.githubusercontent.com/e9t/nsmc/master/ratings.txt>", filename="ratings.txt")
  • request를 이용해 파일을 다운 받아온다.
  • csv파일형식이나 txt파일로 저장되어있다.
train_data = pd.read_table('ratings.txt')
train_data[:5] # 상위 5개 출력
  • read_table: txt파일을 데이터프레임으로 가져오는 함수
len(train_data)

# 200000
  • train_Data가 잘 들어왔는지 확인하면 200000개의 리뷰가 들어온 것을 확인 가능하다.
train_data.isnull().values.any()
# np.True_
  • isnull(): train_data에 null값이 있으면 true가 된다.
  • values: 값만 나오게 된다.(False, True)
  • any(): 한 값이라도 True일경우 np.True_를 반환
**train_data = train_data.dropna(how='any')**
  • Na를 모두 지운다.
train_data['document'] = train_data['document'].str.replace("[^ㄱ-ㅎㅏ-ㅣ가-힣]","")
  • ㄱ~ㅎ, ㅏ~ㅣ, 가~힣: 한글을 제외한 모든 문자는 지워버려
# 불용어 정의
stopwords = ['도', '는', '다', '의', '가', '이', '은', '한', '에', '하', '고', '을', '를', '인', '듯', '과', '와', '네', '들', '듯', '지', '임', '게']
  • 핵심 의미를 담고 있지 않는 단어들으로, 분석 성능을 높이기 위해 사전에 제거하는 단어.

Mecab 형태소 분석

mecab = Mecab(dicpath='C:/mecab/mecab-ko-dic')

mecab.morphs('아버지가방에들어가신다')
# ['아버지', '가', '방', '에', '들어가', '신다']

mecab을 정의하고, mecab안에 문장을 집어 넣게 된다면 위와 같은 결과가 출력된다.

  • mecab을 이용하면 형태소별로 다 단어가 쪼개진다.
  • 그런데 가, 에 등의 조사는 사실상 의미가 없다. 따라서 위에서 등록한 불용어를 이용해준다.
tokenized_data = []
for sentence in train_data['document']:
    temp_X = mecab.morphs(sentence)
    temp_X = [word for word in temp_X if not word in stopwords]
    tokenized_data.append(temp_X)

위처럼 문장을 형태소로 나눈 이후, 불용어를 제거해준다.

이후 해당 단어를 tokenized_data 리스트에 추가해주는 방식

tokenized_data[:3]
# [['어릴', '때', '보', '지금', '다시', '봐도', '재밌', '어요', 'ㅋㅋ'],
#  ['디자인',
#   '배우',
#   '학생',
#   '으로',
#   ',',
#   '외국',
#   '디자이너',
#   '그',
#   '일군',
#   '전통',
#   '통해',
#   '발전',
#   '해',
#   '문화',
#   '산업',
#   '부러웠',
#   '는데',
#   '.',
#   '사실',
#   '우리',
#   '나라',
#   '에서',
#   '그',
#   '어려운',
# ...
#   '음',
#   '.',
#   '.',
#   '최고',
#   '.']]
# Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
  • 위처럼 잘 나눠져 있는 것을 확인 가능하다.

Word2Vec

from gensim.models import Word2Vec

model = Word2Vec(
    sentences=tokenized_data, #학습에 사용할 문장 데이터
    vector_size = 100,# 벡터 표현
    window = 5, # 중심 문자를 기준으로 주변 문자를 보는 범위
    min_count = 5, # 몇 번 이상 등장한 단어만 학습에 포함
    workers = 4, # 데이터를 로드해올때 병렬로 가져오는데 그 cpu를 몇개씩 사용할지
    sg = 0 # 0: CBOW, 1: skipgram(다양하게 학습, 오래걸림) 
 )

문장데이터를 이용하여 실제 벡터로 표현

model.wv.vectors.shape
# (18937, 100)
  • 18937개의 단어를 100차원으로 설명
  • 위에서 설정한 vector_size
model.wv.most_similar('블록버스터')

# [('무협', 0.8200684189796448),
#  ('헐리우드', 0.8104481101036072),
#  ('느와르', 0.7927355170249939),
#  ('호러', 0.7889633178710938),
#  ('sf', 0.7870503664016724),
#  ('히어로', 0.7753642797470093),
#  ('SF', 0.7681315541267395),
#  ('액션물', 0.7672512531280518),
#  ('스릴러물', 0.7659397721290588),
#  ('C', 0.7574071288108826)]
  • 블록버스터라는 단어와 가깝게 설정된 단어 리스트를 출력
  • 확인해보니 대체적으로 영화의 장르가 가깝게 표현된 것이 보인다. 그중 액션관련이 가까움.
model.wv['블록버스터']
# array([-0.0330137 ,  0.6282359 ,  0.42973697, -0.17335516, -0.17651196,
#        -0.6970459 , -0.03660379,  1.071796  , -0.7118055 , -0.30753678,
#        -0.6684205 , -0.36423868,  0.1587452 ,  0.18972148,  0.13022877,
#        -0.79741156, -0.77113366, -0.4358335 ,  0.4195775 , -0.05206894,
#         0.2992659 ,  0.09521263,  0.14125888,  0.44383216,  0.07732219,
#         0.1721758 ,  0.5292899 ,  0.28355977, -0.55120987, -0.15320441,
#         0.3874145 ,  0.14900902,  0.89165574, -0.28329527, -0.29780605,
#         0.18838125,  0.31465304,  0.34367123,  0.3343019 , -0.09478841,
#        -0.00584204, -0.5636469 , -0.32309744, -0.1949582 , -0.5196094 ,
#        -0.1435047 ,  0.11556148,  0.10881115, -0.14614736, -0.41629446,
#         0.47400606, -0.26186278,  0.16051935, -0.42663282,  0.33087805,
#         0.18830375,  0.41369492, -0.00120364, -0.3141201 , -0.2904882 ,
#         0.23806211, -0.11021748, -0.31155202,  0.19804363,  0.67300314,
#         0.46709877,  0.10293837, -0.15151775, -0.9722892 ,  0.18762997,
#        -0.31436935, -0.3784705 ,  0.27354518,  0.1285775 ,  0.14355294,
#         0.02435796, -0.9902095 , -0.4039165 ,  0.12447012,  0.2442918 ,
#         0.18859306,  0.286661  , -0.53241134,  0.01927105, -0.0408907 ,
#         0.01711621,  0.37362412, -0.02828276,  0.70699257,  0.33849493,
#         0.42881256, -0.13219772, -0.49409807,  0.13272044,  0.28636417,
#         0.2736745 ,  0.4566587 , -0.01637852, -0.13629532,  0.23960957],
#       dtype=float32)
  • 해당 단어를 설명하고 있는 100개의 실수 차원
from gensim.models import keyedvectors

model.wv.save_word2vec_format('kor_w2v')
  • 위에서 형태소 분석을 하여 만든 가중치 데이터를 저장해주는 파일

  • 실제로 잘 저장 된 것을 확인할 수 있다.

 

'AI공부 > 자연어처리' 카테고리의 다른 글

5. RNN(Recurrent Neural Network)기초  (1) 2026.02.22
4. FastText  (0) 2026.02.21
2. 자연어 처리(벡터화)  (1) 2026.02.16
1. 자연어처리  (0) 2026.02.16
0. 텐서플로우  (1) 2026.02.14