감성분석 이란?
- 문서의 감성/의견/기분 등을 파악하기 위한 기법으로, 편향없는 기계적인 분석
- 분석에는 두가지 방법이 있는데,
- 사람이 작성한 규칙 기반 알고리즘을 사용 : 특정 단어와 감성 점수의 쌍을 담은 사전(lexicon) 기반이며, VADER 알고리즘(사이킷런)이 있음
- 컴퓨터가 자료로부터 직접 배우는 기계 학습 모형을 사용 : 분류명(레이블)이 붙은 문장 또는 문서 집합을 이용해서 기계 학습 모형을 훈련
AFINN 활용 : -5~5 사이의 점수 할당 (긍정은 양수, 부정은 음수)
- IMDB 영화 리뷰 데이터를 활용 ( 다운로드 : https://www.kaggle.com/datasets/lakshmi25npathi/imdb-dataset-of-50k-movie-reviews )
import pandas as pd
import nltk
from afinn import Afinn
nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
from nltk.tokenize import RegexpTokenizer
import numpy as np
import matplotlib.pyplot as plt
# 분석파일로드
file_name = "IMDB Dataset.csv"
review = pd.read_csv(file_name, engine="python")
review.head(10)
# AFINN 활용 (AFINN: 각 단어 당 -5 ~ 5점으로 구성)
afinn = Afinn()
pos_review = review['review'][1] # 하나의 positive 문장만 출력해 봄
neg_review = review['review'][3] # 하나의 negative 문장만 출력해 봄
print(afinn.score(pos_review))
print(afinn.score(neg_review))
afn = Afinn(emoticons=True)
# 첫 n개 문장 극성분석
n=100
index = []
for row in review['review'][0:n]:
index.append(row)
print(len(index), 'Predicted Sentiment polarity:', afn.score(row))
NRC 활용 : 10가지 감정 용어 사전 이용
- 10가지 감정 : {fear, anger, anticipation, trust, surprise, positive, negative, sadness, disgust, joy}
# NRC 다운로드: https://saifmohammad.com/WebPages/NRC-Emotion-Lexicon.htm
# 감성 사전로드
NRC = pd.read_csv(NRC-Emotion-Lexicon-Wordlevelv0.92.txt, engine="python", header=None, sep="\t")
# 2열이 0 인것은 제외
# 예) abacus는 trust라는 감성에 해당됨, abadon은 fear, negative, sadness 3가지에 해당됨.
NRC = NRC[(NRC != 0).all(1)]
# 인덱스 번호 리셋
NRC = NRC.reset_index(drop=True)
NRC.head(10)
# 특정 한문장 감성분석
pos_review = review['review'][1] # 하나의 positive 문장만 출력해 봄
tokenizer = RegexpTokenizer('[\w]+')
stop_words = stopwords.words('english')
p_stemmer = PorterStemmer()
raw = pos_review.lower() # 분석하려는 문장
tokens = tokenizer.tokenize(raw)
stopped_tokens = [i for i in tokens if not i in stop_words] # 불용어 제거
match_words = [x for x in stopped_tokens if x in list(NRC[0])] # 사전과 매칭
emotion=[]
for i in match_words:
temp = list(NRC.iloc[np.where(NRC[0] == i)[0],1])
for j in temp:
emotion.append(j)
sentiment_result1 = pd.Series(emotion).value_counts()
#감성으로 분류된 단어 빈도 plot 확인
print(sentiment_result1, sentiment_result1.plot.bar())
VADER 어휘사전
- negative, neutral, positive, compound 에 대한 점수 산출
- negative+neutral+positive = 1 이 되도록 구성됨
- compound는 단어의 점수를 합산한 계산되며 -1(극단적 부정) +1(극단적 긍정)으로 Normalize
! pip install vaderSentiment
import nltk
nltk.download('vader_lexicon')
from nltk.sentiment.vader import SentimentIntensityAnalyzer
analyser = SentimentIntensityAnalyzer()
pos_review = review['review'][1] # 하나의 positive 문장만 출력해 봄
score = analyser.polarity_scores(pos_review) # 극성분석
print(score) # compund 가 복합적인 종합점수
# 극성에 따른 분류
def vader_polarity(text):
""" Transform the output to a binary 0/1 result """
score = analyser.polarity_scores(text)
return 1 if score['pos'] > score['neg'] else 0
# 첫 n개 문장만 분석해 보기
n=10
index = []
for row in review['review'][0:n]:
index.append(row)
print(len(index), 'Predicted Sentiment polarity:', analyser.polarity_scores(row))
print(len(index), 'Predicted Sentiment polarity Class:', vader_polarity(row))
SentiWordNet 어휘사전
- positivity, negativity, objectivity 로 분류
import nltk
nltk.download('wordnet')
nltk.download('sentiwordnet')
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet as wn
from nltk.corpus import sentiwordnet as swn
from nltk import sent_tokenize, word_tokenize, pos_tag
lemmatizer = WordNetLemmatizer()
def penn_to_wn(tag):
"""
Convert between the PennTreebank tags to simple Wordnet tags
"""
if tag.startswith('J'):
return wn.ADJ
elif tag.startswith('N'):
return wn.NOUN
elif tag.startswith('R'):
return wn.ADV
elif tag.startswith('V'):
return wn.VERB
return None
def clean_text(text):
text = text.replace("
", " ") # text = text.decode("utf-8")
return text
# 원래는 positivity, negativity, objectivity 3가지 인데, 긍정 부정 2진분류로 변환 시킴
def swn_polarity(text):
"""
Return a sentiment polarity: 0 = negative, 1 = positive
"""
sentiment = 0.0
tokens_count = 0
text = clean_text(text)
raw_sentences = sent_tokenize(text)
for raw_sentence in raw_sentences:
tagged_sentence = pos_tag(word_tokenize(raw_sentence))
for word, tag in tagged_sentence:
wn_tag = penn_to_wn(tag)
if wn_tag not in (wn.NOUN, wn.ADJ, wn.ADV):
continue
lemma = lemmatizer.lemmatize(word, pos=wn_tag)
if not lemma:
continue
synsets = wn.synsets(lemma, pos=wn_tag)
if not synsets:
continue
synset = synsets[0] # Take the first sense, the most common
swn_synset = swn.senti_synset(synset.name())
sentiment += swn_synset.pos_score() - swn_synset.neg_score()
tokens_count += 1
if not tokens_count: # judgment call ? Default to positive or negative
return 0
if sentiment >= 0: # sum greater than 0 => positive sentiment
return 1
return 0 # negative sentiment
# 첫 n개 문장만 분석해 보기
n=10
index = []
for row in review['review'][0:n]:
index.append(row)
#print(len(index), 'Sentiment:', row['sentiment'])
print('Predicted Sentiment polarity:', swn_polarity(row))
TextBlob 활용
- 긍부정 : polatiry [-1 ~ 1]
- 주객관성 : subjectivity [objective:0 ~subjective:1]
!pip install -U textblob
!python -m textblob.download_corpora
댓글남기기