본문 바로가기
머신러닝, 딥러닝/머신러닝

영화리뷰 감성분석 (Sentiment Analysis)

by 장찐 2022. 5. 15.

📚 감성 분석이란 

개념 

 감성분석은 각 문서에 사용된 단어들을 이용하여 해당 문서의 긍정/부정 감성을 파악하는 분석을 의미한다. 감성 분석에는 크게 두 가지 접근방식이 있다. 

 

(1) 머신러닝 기반 접근 : 지도학습

(2) Lexicon Based(감성어 사전 기반) 

 

 최근에는 머신러닝 기반 감성 분석 방법이 많이 사용된다. 한국어 감성 사전이 존재하기는 하지만 공개되어 있는 사전들은 포함된 단어의 수도 적고 특정 도메인에 특화된 방식으로 생성된 것이 많아서 좋은 성능을 기대하기는 어렵다.

 머신러닝으로 지도학습을 하기 위해서는 해당 문서의 감성 라벨링이 되어있어야 하는데, 라벨링 된 채로 공개되는 데이터가 많지 않기 때문에 연구자들이 직접 라벨링을 실시하는 경우도 많다. 

 

 머신러닝 알고리즘 중에서 감성 분석에 자주 사용되는 것은 Logistic Regression이다.

SVM은 성능이 준수해서 여러 연구에서 사용된 사례가 많지만, 학습에 많은 시간이 소요된다.

트리 계열의 알고리즘은 감성 분석에서는 잘 사용되지 않는다. 감성 분석을 위해서는 독립변수로 각 단어가 사용된다. 따라서 단어가 많은 경우에는 백만 개 이상이 사용될 수도 있는데, 트리 계열은 피쳐가 많은 경우에는 제대로 학습되지 않는 경우가 많다. 

 

최근에는 딥러닝 알고리즘(CNN, LSTM)도 많이 사용된다. 가장 최신의 방법으로는 대표적으로 attention 기반의 transformer, bert가 있다.

 


📚 영화 감성 분석 

✅ TF 사용 

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression

#데이터 불러오기 
with open('Korean_movie_reviews_2016.txt', encoding='utf-8') as f:
    docs = [doc.strip().split('\t') for doc in f]
    docs = [(doc[0], int(doc[1])) for doc in docs if len(doc) == 2]
    # To read the second and third column info from each row
    texts, labels = zip(*docs)
    # 둘을 분리해서 별도의 list 변수로 저장

여기서는 기본적인 전처리가 완료된 데이터를 사용한다. 

 

 

#train/test 분리
train_texts, test_texts, train_labels, test_labels = train_test_split(texts, labels, test_size=0.1, random_state=0)

#학습 데이터의 정보로 평가 데이터도 벡터화 해야함. (따로따로 하면 안 됨)
tf_vectorizer = CountVectorizer() 
tf_train_features = tf_vectorizer.fit_transform(train_texts) 
tf_test_features = tf_vectorizer.transform(test_texts)

 

학습 데이터와 평가 데이터는 함께 벡터화를 해야 한다. 별도로 벡터화를 할 경우에는 학습/테스트 데이터셋의 단어 분포가 다르다면 벡터의 단어 순서가 다르게 나타난다. 

 

#로지스틱 회귀 학습
lr_tf = LogisticRegression(max_iter=1000) 
lr_tf.fit(tf_train_features, train_labels) # 학습
pred_labels = lr_tf.predict(tf_test_features)

from sklearn.metrics import accuracy_score
print('Misclassified samples: {} out of {}'.format((pred_labels != test_labels).sum(),len(test_labels)))
print('Accuracy: %.2f' % accuracy_score(test_labels, pred_labels))

전체 영화 리뷰에 대해서 분류를 해서 정확도가 0.89 임을 확인했다. 

 

review_index = 6
print(test_texts[review_index])
print("The predicted value: {} and probability: {}".format(lr_tf.predict(tf_test_features[review_index]), lr_tf.predict_proba(tf_test_features[review_index])))

개별 영화에 대해서도 예측 라벨과 확률을 확인할 수 있다. 

 

 

📌계수 확인 

# Get coefficients of the model 
coefficients = lr_tf.coef_.tolist()

# 학습에 사용된 각 단어마다의 coefficient (즉 weight) 값이 존재
# coefficient값이 큰 순으로 정렬 'reverse=True'
sorted_coefficients = sorted(enumerate(coefficients[0]), key=lambda x:x[1], reverse=True)
print(sorted_coefficients[:5])

단어별 계수도 확인할 수 있다. 여기서는 긍정 라벨리 1이므로, 값이 클수록 긍정 리뷰일 가능성이 높다고 해석할 수 있다. 

 

 

# 긍정 단어 상위 20개
for word, coef in sorted_coefficients[:50]:
    print('{0:} ({1:.3f})'.format(vocablist[word], coef))
    
# 부정 단어 상위 20개
for word, coef in sorted_coefficients[-20:]:
    print('{0:} ({1:.3f})'.format(vocablist[word], coef))

긍정 단어 상위 20
부정 단어 상위 20

긍정/부정 단어의 계수가 큰 순서대로 출력하면 다음과 같다. 전반적으로 상식적인 결과가 순서대로 출력된 것을 확인할 수 있다. '존잼', '꿀잼' 등의 단어가 포함되면 긍정 리뷰일 가능성이 높고, '최악', '노잼' 등의 단어가 포함되면 부정 리뷰일 가능성이 높다. 

 

 

✅ TF - IDF 사용 

tfidf_vectorizer = TfidfVectorizer() 
tfidf_train_features = tfidf_vectorizer.fit_transform(train_texts) 
tfidf_test_features = tfidf_vectorizer.transform(test_texts)

이후 과정은 TF를 사용한 방식과 동일하다. 문서 감성 분석을 할 때, TF가 좋은지 TF-IDF 좋은지에 대한 명확한 기준은 없다. 반드시 TF-IDF 방식이 좋은 것은 아니기 때문에 해봐야 할 수 있다. 

 

 

 


📚  Reference

 

 

 

 

댓글