
Lexicon vs. Transformers: VADER와 RoBERTa를 활용한 감성 분석(Sentiment Analysis) 완전 가이드
요약
VADER 어휘 기반 방식과 RoBERTa 트랜스포머 기반 방식을 비교하여 감성 분석 워크플로우를 설명합니다. 데이터 전처리부터 모델 비교, Streamlit을 활용한 대화형 대시보드 구현까지의 전 과정을 다룹니다.
핵심 포인트
- VADER와 RoBERTa의 방법론적 차이 및 장단점 비교
- NLTK를 활용한 텍득 전처리 및 EDA 과정
- Transformer 모델의 문맥 이해 능력 및 성능 분석
- Streamlit과 Hugging Face를 이용한 실무형 애플리케이션 구축
현대 자연어 처리 (NLP) 분야에서 텍스트 데이터로부터 인간의 감정과 감성(Sentiment)을 이해하는 것은 매우 요구되는 능력입니다. 고객 피드백, 제품 리뷰 또는 소셜 미디어 트렌드를 분석하든, 적절한 모델링 패러다임을 선택하는 것은 매우 중요합니다. 이 종합 가이드는 어휘 기반의 Bag-of-words 접근 방식 (VADER)과 딥러닝 트랜스포머 (Transformer) 기반 접근 방식 (RoBERTa)을 비교하는 완전한 감성 분석 워크플로우를 상세히 설명하며, 실시간 모델 테스트를 위한 대화형 Streamlit 대시보드로 마무리합니다.
목차
- 감성 분석 (Sentiment Analysis) 소개
- 데이터셋 준비 및 탐색적 데이터 분석 (EDA)
- NLTK 텍스트 전처리
- VADER 어휘 기반 감성 분석
- RoBERTa 트랜스포머 기반 감성 분석
- 모델 비교 및 예외 사례 (Edge Cases)
- 대화형 Streamlit 애플리케이션
- 프로덕션을 위한 Hugging Face 파이프라인 (Pipelines)
- 프로젝트 링크 및 리소스
감성 분석 (Sentiment Analysis) 소개
감성 분석 (Sentiment Analysis, 또는 의견 마이닝)은 개체, 개인, 이슈 또는 사건에 대한 사람들의 의견, 감성 및 감정을 계산적으로 연구하는 것입니다. 이 프로젝트에서는 두 가지 뚜렷한 방법론을 탐구합니다:
- VADER (Valence Aware Dictionary and sEntiment Reasoner): 소셜 미디어와 제품 리뷰에서 표현되는 감성에 특별히 맞춰진 어휘(Lexicon) 및 규칙 기반 감성 분석 도구입니다. 이는 감정적 강도(Valence)에 매핑된 사전 정의된 단어 사전에 의존합니다.
- RoBERTa (Robustly Optimized BERT Pretraining Approach): Google의 BERT (Bidirectional Encoder Representations from Transformers)를 최적화한 변형 모델입니다. 셀프 어텐션 (Self-attention) 메커니즘을 활용함으로써, RoBERTa는 단어 사이의 양방향 문맥 의존성을 포착하여 비꼬는 표현 (Sarcasm), 부정 (Negations) 및 미묘한 언어적 뉘앙스를 인식하는 데 훨씬 뛰어난 성능을 발휘합니다.
| 특징 / 지표 | VADER (어휘 기반) | RoBERTa (Transformer 기반) |
|---|---|---|
| 기저 접근 방식 | 어휘 및 규칙 기반 (Bag-of-words) | Transformer 기반 (Self-Attention) |
| ... |
데이터셋 준비 및 탐색적 데이터 분석 (Exploratory Data Analysis)
이 모델들을 시연하기 위해, 우리는 Amazon Fine Food Reviews 데이터셋(Reviews.csv)을 활용합니다. 이 데이터셋은 Amazon의 고급 식품에 대한 사용자 리뷰를 포함하고 있으며, 텍스트 리뷰와 그에 따른 1~5점 별점(star ratings)이 포함되어 있습니다.
데이터셋 초기화 및 축소
개발 과정 중 연산 오버헤드(computational overhead)를 낮게 유지하기 위해, 처음 500개의 레코드만 가져옵니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
...
클래스 불균형 시각화 (Class Balance Visualization)
별점 분포를 시각화하는 것은 모델 편향(model bias)을 이해하는 데 매우 중요한 클래스 불균형(class imbalance)을 식별하는 데 도움이 됩니다.
ax = df['Score'].value_counts().sort_index().plot(
kind='bar',
title='Count of Reviews by Star Rating',
...
Amazon Fine Food Reviews 데이터셋은 5점 별점(매우 긍정적) 쪽으로 매우 치우쳐져(skewed) 있으며, 이는 소비자 피드백 데이터셋에서 흔히 나타나는 특징입니다.
NLTK 텍스트 전처리 (NLTK Text Preprocessing)
어휘 엔진을 실행하기 전에, Natural Language Toolkit (NLTK)을 활용하여 전통적인 언어학적 전처리 단계를 탐색합니다. 이러한 단계들은 토큰화 (tokenization), 품사 태깅 (Part-of-Speech (POS) tagging), 그리고 개체명 인식 (Named Entity Recognition (NER))을 이해하는 데 도움을 줍니다.
import nltk
# 필요한 NLTK 리소스 다운로드
...
파이프라인 이해하기:
- 토큰화 (Tokenization): 연속된 텍스트를 개별 단어 또는 문장 부호로 분리합니다.
- 품사 태깅 (POS Tagging): 각 토큰의 문법적 역할(예: 명사
NN, 형용사JJ, 현재형 동사VBZ)을 식별합니다. - 개체명 인식 (NER): 토큰을
PERSON(인물),ORGANIZATION(조직), 또는GPE(지정학적 엔티티)와 같은 구조화된 엔티티로 클러스터링합니다.
VADER 어휘 기반 감성 분석 (Lexicon-Based Sentiment Analysis)
VADER는 강도 등급(intensity ratings)에 매핑된 어휘적 특징(lexical features) 사전(dictionary)을 사용합니다. 예를 들어, "good"은 긍정적이고, "great"는 더 긍정적이며, "excellent"는 훨씬 더 긍정적입니다. 또한 대문자 사용("GREAT"는 "great"보다 강함) 및 느낌표("great!"가 더 강함)에 대한 휴리스틱(heuristics)을 적용합니다.
VADER를 활용한 단일 문장 추론 (Single Sentence Inference)
from nltk.sentiment import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')
...
VADER를 이용한 데이터셋 처리
500개의 모든 리뷰에 대해 VADER를 실행하고, 결합 점수(compound), 긍정(positive), 중립(neutral), 부정(negative) 점수를 원래의 데이터프레임(dataframe)에 다시 병합합니다.
from tqdm.notebook import tqdm
res = {}
...
VADER 가정 시각화
VADER가 고객 평점과 일치하는지 확인하기 위해, 전체 결합 점수 (Compound Score) (-1에서 1 사이의 범위)와 개별 감성 카테고리(긍정, 중립, 부정)를 Amazon의 별점 리뷰 (Star Review) 점수(1에서 5)에 대해 플롯(plot)합니다.
Amazon 별점 리뷰별 결합 점수
결합 점수는 텍스트 내 각 단어의 가치 점수(valence scores)를 합산하여 -1(가장 부정적)에서 1(가장 긍정적) 사이로 정규화한 단일 지표입니다.
# VADER 결합 점수 플롯
ax = sns.barplot(data=vaders, x='Score', y='compound')
ax.set_title('Compound Score by Amazon Star Review')
...
분석 (Analysis): 별점이 1개에서 5개로 증가함에 따라 복합 점수 (Compound score)가 부정에서 강한 긍정으로 선형적으로 증가하며, 이는 사용자 별점과 명확한 양의 상관관계 (Positive correlation)를 보여줍니다.
개별 감성 카테고리 (Individual Sentiment Categories)
우리는 다양한 별점에 걸쳐 감성을 긍정 (Positive), 중립 (Neutral), 부정 (Negative) 점수로 세분화합니다.
fig, axs = plt.subplots(1, 3, figsize=(15, 5))
sns.barplot(data=vaders, x='Score', y='pos', ax=axs[0])
sns.barplot(data=vaders, x='Score', y='neu', ax=axs[1])
...
가정 확인 (Assumption Check): 예상대로 별점이 높을수록 긍정 점수는 점진적으로 상승하는 반면, 부정 점수는 별점 5개 리뷰에서 0에 가깝게 하락하는 추세를 보입니다.
RoBERTa 트랜스포머 기반 감성 분석 (RoBERTa Transformer-Based Sentiment Analysis)
VADER의 조회 사전 (Lookup dictionary) 방식과 달리, RoBERTa는 단어 시퀀스를 동적으로 처리합니다. 어텐션 헤드 (Attention heads)를 활용함으로써, 모델은 단어들이 서로 어떻게 상호작용하는지에 대한 문맥 (Context)을 학습합니다. 우리는 약 5,800만 개의 트윗으로 학습되고 감성 탐지에 특화되어 미세 조정 (Fine-tuned)된 RoBERTa 모델인 cardiffnlp/twitter-roberta-base-sentiment를 사용합니다.
HuggingFace를 통한 RoBERTa 로드 (Loading RoBERTa with HuggingFace)
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from scipy.special import softmax
import torch
...
RoBERTa를 이용한 단일 문장 추론 (Single Sentence Inference with RoBERTa)
추론 (Inference)을 실행하기 위해, 텍스트를 인코딩 (Encode)하고, 가공되지 않은 예측 로짓 (Raw prediction logits)을 가져온 뒤, 소프트맥스 (Softmax) 활성화 함수를 적용하여 가공되지 않은 출력을 확률 분포 (Probability distributions)로 변환합니다.
# 입력값 토큰화 및 인코딩
encoded_text = tokenizer(example, return_tensors='pt')
...
RoBERTa를 이용한 데이터셋 반복 처리 (Iterating Over the Dataset with RoBERTa)
우리는 표준 CPU 또는 GPU (CUDA 사용)에서 실행할 수 있는 견고한 극성 추출 래퍼 (polarity-extracting wrapper)를 작성합니다. 장치 불가지론적 (device-agnostic) 접근 방식을 활용하면 최대의 호환성과 높은 처리량의 배치 처리 (batch processing)를 보장할 수 있습니다.
CPU 전용 구현 (CPU-Only Implementation)
로컬 프로토타이핑, 저전력 엣지 머신(edge machines) 또는 전용 그래픽 카드가 없는 환경에 이상적입니다.
def roberta_polarity_cpu(text_sample):
model.to('cpu') # 모델을 CPU로 강제 지정
encoded_text = tokenizer(
...
GPU 가속 구현 (GPU-Accelerated Implementation)
대규모 프로덕션 실행에 권장되며, CUDA 코어에서의 병렬화된 행렬 연산을 통해 추론 (inference) 속도를 수십 배 향상시킵니다.
def roberta_polarity_gpu(text_sample):
# 장치를 동적으로 선택
device = "cuda" if torch.cuda.is_available() else "cpu"
...
두 모델을 동시에 처리하고 결과 저장
res = {}
for i, row in tqdm(df.iterrows(), total=len(df)):
text = row['Text']
...
모델 비교 및 예외 사례 (Model Comparison and Edge Cases)
사전 기반 (lexicon-based) 점수와 심층 문맥 임베딩 (deep contextual embeddings)을 비교하면 상당한 행동 차이가 드러납니다.
페어플롯 분석 (Pairplot Analysis)
Seaborn을 사용하여 모든 평점에 걸쳐 VADER 점수와 RoBERTa 점수 사이의 상관관계와 분리도를 시각화합니다.
sns.pairplot(
data=result_df,
vars=['vader_neg', 'vader_pos', 'roberta_neg', 'roberta_pos'],
...
RoBERTa는 클러스터에서 훨씬 더 깔끔한 분리 성능을 보여줍니다. 별점이 높은 평점은 낮은 roberta_neg와 높은 roberta_pos 주변에 엄격하게 모이는 반면, VADER는 겹치고 노이즈가 많은 산점도 (scatter layouts)를 나타냅니다.
예외 사례 1: 비꼬는 말투의 별점 1점 리뷰 (Sarcastic 1-Star Reviews)
고객이 긍정적인 단어를 비꼬는 의도로 사용하는 별점 1점 리뷰를 생각해 봅시다:
"이 제품들을 받게 되어 정말 기대했는데, 완전히 눅눅하고 아무 맛도 없네요. 완전히 돈 낭비입니다.""
- VADER의 해석: "excited"와 같은 긍정적인 어휘 항목(lexical entries)을 감지하여 중립(neutral) 또는 약간 긍정적(slightly positive)으로 중간 점수를 부여합니다.
- RoBERTa의 해석: 대조적인 변화를 감지하여 이를 강력한 **부정(Negative, neg ~0.95)**으로 정확하게 분류합니다.
# 별점 1점 리뷰에서 극단적인 긍정 불일치(positive mismatch) 쿼리
sarcastic_review = result_df.query('Score == 1').sort_values('roberta_pos', ascending=False)['Text'].values[0]
print(f"RoBERTa가 가장 긍정적으로 평가한 별점 1점 리뷰:\n{sarcastic_review}")
에지 케이스 2: 매우 냉소적인 별점 5점 리뷰 (Edge Case 2: Highly Cynical 5-Star Reviews)
고객이 "위험할 정도로 중독적인(dangerously addictive)"과 같은 단어를 사용하는 별점 5점 리뷰를 생각해 봅시다:
"이 초콜릿은 위험할 정도로 맛있어요. 먹는 것을 멈출 수가 없네요. 심각한 문제예요.""
- VADER의 해석: "dangerously" 및 "problem"과 같이 매우 부정적인 토큰(tokens)을 포착하여 감성을 중립(neutral) 또는 부정(negative)으로 표시합니다.
- RoBERTa의 해석: 문맥적 흐름(contextual flow)을 분석하여 "dangerously good"의 과장된 특성을 이해하고, 이를 매우 **긍정(Positive, pos ~0.98)**으로 표시합니다.
# 별점 5점 리뷰에서 극단적인 부정 불일치(negative mismatch) 쿼리 (매우 냉소적인 긍정 댓글)
cynical_review = result_df.query('Score == 5').sort_values('roberta_neg', ascending=False)['Text'].values[0]
print(f"RoBERTa가 가장 부정적으로 평가한 별점 5점 리뷰:\n{cynical_review}")
대화형 Streamlit 애플리케이션 (Interactive Streamlit Application)
이 분석을 배포하고 접근 가능하게 만들기 위해, Streamlit을 사용하여 가볍고 성능이 뛰어난 웹 대시보드를 구축합니다. 이 애플리케이션은 두 모델을 모두 로드하고, 메모리 팽창(memory bloat)을 방지하기 위해 모델을 캐싱(caching)하며, 나란히 비교할 수 있는 그래프를 제공합니다.
# streamlit_app.py
import nltk
import pandas as pd
import streamlit as st
from nltk.sentiment import SentimentIntensityAnalyzer
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import warnings
import logging
Hugging Face 경고 억제
logging.getLogger("transformers").setLevel(logging.ERROR)
warnings.filterwarnings('ignore')
VADER Lexicon 다운로드 보장
try:
nltk.data.find('vader_lexicon')
except LookupError:
nltk.download('vader_lexicon', quiet=True)
페이지 메타데이터 설정
st.set_page_config(page_title="Review Sentiment Analysis", layout='wide')
st.title("Review Sentiment Analysis App")
st.write("VADER 및 RoBERTa 모델을 사용하여 리뷰 감성 (Sentiment)을 동적으로 분석합니다.")
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기

