Single-polarity sentiment analysis는 문장의 감정을 긍정/부정/중립으로 나눠서 분석한다.
하지만 부정적인 감정에는 공포와 불안 등 여러 가지 감정이 있으며 긍정적인 감정에도 여러 가지 감정들이 있다.
Ekman은 자신의 논문 An Argument for Basic Emotions: Cognition and Emotion 을 통해 감정을 ANGER, DISGUST, FEAR, HAPPINESS, SADNESS, SURPRISE 로 나누었다. 영어의 경우 트위터, 댓글, 온라인 뉴스 데이터와 Ekman의 7가지 감정 분류를 활용한 multi-category classification emotion analysis 에 대한 연구가 활발하다.
하지만 한국어의 감정 분석은 대부분 Single-polarity(긍정/부정)에 머물고 있다. 그 이유에는 여러가지가 있지만 가장 큰 문제점은 한국어의 교착성이다. 한국어의 경우 영어와는 다르게 형태소별로 나눌 수 있는 교착어로 이루어져 있어 상대적으로 감성 사전을 구축하는 것이 어렵다. 감정 사전 구축이 어렵다보니 한국어의 감정 분석은 Multi-polarity로 나아가지 못하고 single-polarity에 머물고 있다.
이로 인하여 여러 카테고리의 감성 분석 결과를 여론조사에 활용하며 기존의 기존의 통계적 분석을 대체하고 있는 미국과는 다르게 한국은 한정적인 분야에서만 감성 분석 결과를 사용하고 있다. 따라서 본 연구를 통해 한국어 문장 속에서 주요 감정들을 분석할 수 있도록 하는 방법론을 제시하고 한국어 문장의 emotion analysis에 특화된 기계 학습 모델을 찾고자 한다.
먼저 사전에 구축한 영어 감성사전과 한국어 데이터를 구글, 파파고, 카카오 NMT API를 통해 번역한 영문 번역 데이터를 제작하고 그 결과를 mLSTM, Transformer, Multi-class SVM kernels 모델에 대입해본다. 이후 총 아홉 가지의 데이터-모델 조합의 output을 비교하고, 최적의 조합을 제시한다.
7가지 감정 카테고리(happy, sad, anger, disgust, surprise, fear, neutral) classification을 위해 아래의 세 가지 labeled emotion data를 사용하였다. 각 감정 카테고리 별 최대 2000개의 라벨링 문장을 통합하여 감정 분석 모델을 구축하는 training data set으로 사용하였다.
- https://www.kaggle.com/praveengovi/emotions-dataset-for-nlp
- https://www.kaggle.com/c/sa-emotions/data
- https://www.kaggle.com/eray1yildiz/using-lstms-with-attention-for-emotion-recognition/data
Emotion | Count |
---|---|
anger | 2000 |
disgust | 1948 |
fear | 2000 |
happiness | 2000 |
neutral | 2000 |
sadness | 2000 |
surprise | 2000 |
- 트위터 데이터 크롤링
Tweeter Crawling API로 TWEEPY가 있으나 최근 7일 데이터만 수집할 수 있는 한계가 있다.
그 이전의 데이터를 수집하고 싶으면 Premium-Api를 구매해야 하는데 500request에 $149/월 이다.
따라서 오픈소스로 많이 사용하는 twitterscraper package를 사용하려고 한다.
데이터는 총선을 키워드로 검색하였다.try: from twitterscraper.query import query_tweets from twitterscraper.tweet import Tweet except: !pip install twitterscraper from twitterscraper.query import query_tweets from twitterscr list_of_tweets = query_tweets('총선', begindate=datetime.date(2020,4,1), enddate=datetime.date(2020,4,30))
- Twitter 데이터 전처리
데이터 전처리를 위하여 Soyspacing 패키지를 사용하였다. 추가적으로 링크, 트위터 아이디 등을 불용어처리 하였다.remove_hypterlink = re.sub(r"http\S+", "", sentence['content']) # 하이퍼링크 제거 remove_twitterlink = re.sub(r"pic\S+", "", remove_hypterlink) # 트위터링크 제거 remove_retweet = re.sub(r"@\S+", "", remove_twitterlink) # 트위터아이디 제거
-
영화 데이터 크롤링
7가지의 감정을 잘 예측하였는지 확인하기 위한 test set으로서 영화 리뷰 데이터를 활용하였다. 그 이유는 영화 리뷰는 영화를 본 후 감상평을 적는 것이기 때문에 사람들의 7가지 감정이 잘 녹아들어 있을 거라 판단했기 때문이다.영화 데이터는 NSMC의 네이버 영화 리뷰 데이터를 긍정/부정으로 분류한 자료를 활용하였다. 해당 데이터는 총 20만 개의 네이버 영화 리뷰가 담겨있었으며 부정(0)과 긍정(1)로 레이블링이 되어있었다. 그리고 Large Movie Review Dataset(Maas et al, 2011)를 참조하여 데이터를 구축하였다는 점에서 신뢰도가 있었고 140자 이내 길이의 문장들이 있다는 점이 train set과 유사하였다.
해당 데이터는 긍정과 부정이라는 2개의 감정으로 레이블링이 되어있지만 본 연구는 7가지의 감정을 예측하고자 하였기 때문에 기존 긍정과 부정 레이블링은 제거하여 사용하였다.
-
영화 데이터 전처리
긍정과 부정으로 레이블링 되어있는 것을 제거하고 자음, 특수문자 그리고 불필요한 공백을 제거하였다.#문자마다 마지막에 있는 0,1 값 제거 data_train = [line.strip('0') for line in data_train] data_train = [line.strip('1') for line in data_train] data_train = [line.strip('\t') for line in data_train] data_train = [line.replace('\t',' ' ) for line in data_train] #자음 제거 data_train = [line.replace('ㅋ','' ) for line in data_train] data_train = [line.replace('ㅜ','' ) for line in data_train] data_train = [line.replace('ㅠ','' ) for line in data_train] data_train = [line.replace('ㅎ','' ) for line in data_train] data_train = [line.replace('ㄱ','' ) for line in data_train] data_train = [line.replace('ㅉ','' ) for line in data_train] data_train = [line.replace('ㅅ','' ) for line in data_train] data_train = [line.replace('ㅂ','' ) for line in data_train] data_train = [line.replace('ㅈ','' ) for line in data_train] data_train = [line.replace('ㅊ','' ) for line in data_train] data_train = [line.replace('ㅏ','' ) for line in data_train] #특수 문자 제거 data_train = [line.replace('*','' ) for line in data_train] data_train = [line.replace(';','' ) for line in data_train] data_train = [line.replace('♥','' ) for line in data_train] data_train = [line.replace('/','' ) for line in data_train] data_train = [line.replace('♡','' ) for line in data_train] data_train = [line.replace('>','' ) for line in data_train] data_train = [line.replace('<','' ) for line in data_train] data_train = [line.replace('-','' ) for line in data_train] data_train = [line.replace('_','' ) for line in data_train] data_train = [line.replace('+','' ) for line in data_train] data_train = [line.replace('=','' ) for line in data_train] data_train = [line.replace('"','' ) for line in data_train] data_train = [line.replace('~','' ) for line in data_train] data_train = [line.replace('^','' ) for line in data_train] #숫자 제거 data_train = [line.replace('0','' ) for line in data_train] data_train = [line.replace('1','' ) for line in data_train] data_train = [line.replace('2','' ) for line in data_train] data_train = [line.replace('3','' ) for line in data_train] data_train = [line.replace('4','' ) for line in data_train] data_train = [line.replace('5','' ) for line in data_train] data_train = [line.replace('6','' ) for line in data_train] data_train = [line.replace('7','' ) for line in data_train] data_train = [line.replace('8','' ) for line in data_train] data_train = [line.replace('9','' ) for line in data_train] #왼쪽 공백 제거 data_train = [line.lstrip( ) for line in data_train] #오른쪽 공백 제거 data_train = [line.rstrip( ) for line in data_train]
- Google NMT API
Google NMT API는 The Python Package Index(PyPI) 에 올라와 있는 공식 API 사용 예제에 따라 구현하였다.
from googletrans import Translator
for i in range(len(data_train)):
string = data_train[i]
translator = Translator(proxies=None, timeout=None)
result = translator.translate(string, dest="en")
print(result.text)
- Naver Papago NMT API
Papago NMT API는 Naver Developers에 올라와 있는 공식 API 사용 예제에 따라 구현하였다.
이후 결과를 JSON파일로 저장하여 Input 데이터로 사용하기 쉽게 저장하였다.
if(rescode==200):
response_body = response.read()
# Json format
result = json.loads(response_body.decode('utf-8'))
pprint(result)
# Json result
with open('Crawler\\translated_files\\translated_0401_0402.txt', 'w', encoding='utf8') as f:
f. write(result['message']['result']['translatedText'])
else:
print("Error Code:" + rescode)
- Kakao NMT API
공식 번역 개발 가이드를 참고하여 Kakao NMT API를 구현하였다.
URL = 'https://kapi.kakao.com/v1/translation/translate'
APP_KEY = {APP KEY}
r = requests.get(URL, headers=headers, params = paras )
json_data = json.loads(r.text)
trans_text = json_data.get('translated_text')
각 NMT API별로 MSVM, mLSTM Attention, Transformer를 조합하여 분석한 총 200개의 결과 중 상위 24개 데이터이다. 또한 Movie 데이터와 Twitter 데이터에 두드러지는 차이점이 존재하기 때문에 Movie 데이터만 사용했을 때의 Precision과 Twitter 데이터만 사용했을 때의 Precision, 그리고 두 데이터를 모두 사용했을 때의 Precision을 모두 측정하였다.
라벨 | 구글 | 카카오 | 파파고 | ||||||
---|---|---|---|---|---|---|---|---|---|
mSVM | mLSTM | TF | mSVM | mLSTM | TF | mSVM | mLSTM | TF | |
Movie | 35 | 39 | 32 | 31 | 39 | 29 | 34 | 36 | 27 |
57 | 34 | 24 | 57 | 32 | 16 | 51 | 37 | 16 | |
Total | 92 | 73 | 56 | 88 | 71 | 45 | 85 | 73 | 43 |
M_Precision | 0.35 | 0.39 | 0.32 | 0.31 | 0.39 | 0.29 | 0.34 | 0.36 | 0.27 |
T_Precision | 0.57 | 0.34 | 0.24 | 0.57 | 0.32 | 0.16 | 0.51 | 0.37 | 0.16 |
Total Precision | 0.46 | 0.365 | 0.28 | 0.44 | 0.355 | 0.225 | 0.425 | 0.365 | 0.215 |
-
구글 NMT API + Model Precision
- 영화 데이터: mLSTM + Attention - 0.39
- 트위터 데이터: mSVM - 0.39
- 모든 데이터: mSVM - 0.36
-
카카오 NMT API + Model Precision
- 영화 데이터: mLSTM + Attention - 0.39
- 트위터 데이터: mSVM - 0.57
- 모든 데이터: mSVM - 0.44
-
파파고 NMT API + Model Precision
- 영화 데이터: mLSTM + Attention - 0.36
- 트위터 데이터: mSVM - 0.51
- 모든 데이터: mSVM - 0.43
각 모델별로 Google, Kakao, Papago NMT API를 조합하여 분석한 결과의 상위 24개 데이터이다.
라벨 | mSVM | mLSTM | TF | ||||||
---|---|---|---|---|---|---|---|---|---|
구글 | 카카오 | 파파고 | 구글 | 카카오 | 파파고 | 구글 | 카카오 | 파파고 | |
Movie | 35 | 31 | 34 | 39 | 39 | 36 | 32 | 29 | 27 |
57 | 57 | 25 | 34 | 32 | 37 | 24 | 16 | 16 | |
Total | 92 | 88 | 85 | 73 | 71 | 73 | 56 | 45 | 43 |
M_Precision | 0.35 | 0.31 | 0.34 | 0.39 | 0.39 | 0.36 | 0.32 | 0.29 | 0.27 |
T_Precision | 0.57 | 0.57 | 0.51 | 0.34 | 0.32 | 0.37 | 0.24 | 0.16 | 0.16 |
Total Precision | 0.46 | 0.44 | 0.43 | 0.37 | 0.36 | 0.37 | 0.28 | 0.23 | 0.22 |
-
mSVM + NMT API Precision
- 영화 데이터: 구글 NMT API - 0.35
- 트위터 데이터: 구글 or 카카오 NMT API - 0.57
- 모든 데이터: 구글 NMT API - 0.46
-
mLSTM Attention + NMT API Precision
- 영화 데이터: 구글 or 카카오 NMT API - 0.39
- 트위터 데이터: 파파고 NMT API - 0.37
- 모든 데이터: 구글 or 파파고 NMT API - 0.37
-
Transformer + NMT API Precision
- 영화 데이터: 구글 NMT API - 0.32
- 트위터 데이터: 구글 NMT API - 0.24
- 모든 데이터: 구글 NMT API - 0.28
- 영화 데이터: 구글 or 카카오 NMT API + mLSTM Attention - 0.39
- 트위터 데이터: 구글 or 카카오 NMT API + mSVM - 0.57
- 총 데이터: 구글 NMT API + mSVM - 0.46
Model | NMT API | Precision | |
---|---|---|---|
영화 데이터 | MLSTM | Google/Kakao | 0.39 |
트위터 데이터 | MSVM | Google/Kakao | 0.57 |
총평 | MSVM | 0.46 |
따라서 영화 리뷰 데이터와 같이 문장이 짧고 감정이 다양한 Input Data를 사용할 경우에는 구글 또는 카카오 NPT API와 mLSTM + Attention 모델 조합을 사용하는 것이 성능이 가장 우수하다는 것을 알 수 있다.
트위터 데이터와 같이 문장이 대체적으로 길고 감정이 한정적인 Input Data를 사용할 경우에는 구글 또는 카카오 NPT API와 mSVM 모델 조합을을 사용하는 것이 가장 우수하다.
전체 데이터를 사용했을 때는 구글 데이터와 mSVM 모델 조합을 사용했을 경우 0.46으로 성능이 가장 우수하였다.
- 최종 보고서: Final Report
- 시연 영상: Demo Video