감성 분석
: 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법으로 소셜미디어, 여론조사, 온라인 리뷰, 피드백 등 다양한 분야에서 활용되고 있음.
: 문서 내 텍스트가 나타내는 여러가지 주관적인 단어와 문맥을 기반으로 감성 수치를 계산하는 방법 이용.
: 긍정 감성 지수와 부정 감성 지수로 구성되며 이들 지수를 합산해 긍정감성 또는 부정감성을 결정함.
- 지도학습의 방식
: 학습 데이터와 타깃레이블 값을 기반으로 감성분석 학습을 진행한 뒤 이를 기반으로 다른 데이터의 감성 분석을 예측하는 방법으로 일반적인 텍스트 기반의 분류와 거의 동일.
- 비지도 학습의 방식
‘Lexicon’이라는 일종의 감성 어휘사전 이용, 감성 분석을 위한 용어와 문맥에 대한 다양한 정보를 가지고 있으며, 이를 이용해 문서의 긍정적, 부정적 감성여부를 파악함.
- 지도학습 기반 감성분석 실습 - IMDB 영화평
import pandas as pd
review_df = pd.read_csv('./labeledTrainData.tsv', header=0, sep = '\t', quoting =3) #탭(\t) 문자로 분리된 파일. 인자로 sep 명시.
import re
#<br> html 태그는 replace 함수로 공백으로 변환
review_df['review'] = review_df['review'].str.replace('<br />', ' ')
#파이썬의 정규 표현식 모듈인 re를 이용해 영어 문자열이 아닌 문자는 모두 공백으로 변환
review_df['review'] = review_df['review'].apply(lambda x : re.sub("[^a-zA-Z]", " ", x) )
# 이제 결정 값 클래스인 sentiment 칼럼 별도로 추출해서 결정값 데이터 세트 만들고, 원본 데이터 세트에서 id와 sentiment 컬럼을 삭제해 피처 데이터 세트 생성하면 됨.
# 이후는 앞에 텍스트 분석과 동일
**정규표현식 짚고 넘어가기






- 비지도학습 기반 감성 분석 소개
많은 감성 분석용 데이터는 결정된 레이블 값을 가지고 있지 않음.
* 감성 사전
: 긍정 또는 부정 감성의 정도를 의미하는 수치를 가지고 있으며 이를 감성 지수(Polarity Score)라고 함.
이 감성 지수는 단어이 위치나 주변 단어, 문맥, POS(품사) 등을 참고해 결정됨 - NLTK 패키지
- NLP 패키지의 WordNet
: 다양한 상황에서 같은 어휘라도 다르게 사용되는 어휘의 시맨틱 정보를 제공하며,
이를 위해 각각의 품사로 구성된 개별 단어를 Synset이라는 개념을 이용해 표현.
Synset은 단순한 하나의 단어가 아니라, 그 단어가 가지는 문맥, 시맨틱 정보를 제공하는 WordNet의 핵심 개념!
but, 예측 성능 안좋음.
- SentiWordNet
: synset 별로 긍정감성지수, 부정감성지수, 객관성 지수와 같은 3가지 감성점수를 할당함. 객관성 지수는 긍정/부정 감성 지수와 완전히 반대되는 개념으로 단어가 감성과 관계없이 얼마나 객관적인지 수치로 나타냄. 문장별로 단어들의 긍정 감성지수와 부정감성지수를 합산하여 최종 감성지수를 계산.
+ VADER, Pattern
- SentiWordNet을 이용한 영화 감상평 감성 분석
- 문서를 문장 단위로 분해
- 다시 문장을 단어 단위로 토큰화하고 품사 태깅
- 품사 태깅된 단어 기반으로 synset 객체와 senti_synset 객체를 생성
- senti_synset에서 긍정감성/부정감성 지수를 구하고 이를 모두 합산해 특정 임계치 값 이상일 때 긍정 감성으로, 그렇지 않을 때는 부정 감성으로 결정
from nltk.corpus import wordnet as wn
# 간단한 NTLK PennTreebank Tag를 기반으로 WordNet기반의 품사 Tag로 변환
def penn_to_wn(tag):
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
from nltk.stem import WordNetLemmatizer
from nltk.corpus import sentiwordnet as swn
from nltk import sent_tokenize, word_tokenize, pos_tag
def swn_polarity(text):
# 감성 지수 초기화
sentiment = 0.0
tokens_count = 0
lemmatizer = WordNetLemmatizer()
raw_sentences = sent_tokenize(text)
# 분해된 문장별로 단어 토큰 -> 품사 태깅 후에 SentiSynset 생성 -> 감성 지수 합산
for raw_sentence in raw_sentences:
# NTLK 기반의 품사 태깅 문장 추출
tagged_sentence = pos_tag(word_tokenize(raw_sentence))
for word , tag in tagged_sentence:
# WordNet 기반 품사 태깅과 어근 추출
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
# 어근을 추출한 단어와 WordNet 기반 품사 태깅을 입력해 Synset 객체를 생성.
synsets = wn.synsets(lemma , pos=wn_tag)
if not synsets:
continue
# sentiwordnet의 감성 단어 분석으로 감성 synset 추출
# 모든 단어에 대해 긍정 감성 지수는 +로 부정 감성 지수는 -로 합산해 감성 지수 계산.
synset = synsets[0]
swn_synset = swn.senti_synset(synset.name())
sentiment += (swn_synset.pos_score() - swn_synset.neg_score())
tokens_count += 1
if not tokens_count:
return 0
# 총 score가 0 이상일 경우 긍정(Positive) 1, 그렇지 않을 경우 부정(Negative) 0 반환
if sentiment >= 0 :
return 1
return 0
review_df['preds'] = review_df['review'].apply( lambda x : swn_polarity(x) )
y_target = review_df['sentiment'].values
preds = review_df['preds'].values
from sklearn.metrics import accuracy_score, confusion_matrix, precision_score
from sklearn.metrics import recall_score, f1_score, roc_auc_score
import numpy as np
print(confusion_matrix( y_target, preds))
print("정확도:", np.round(accuracy_score(y_target , preds), 4))
print("정밀도:", np.round(precision_score(y_target , preds),4))
print("재현율:", np.round(recall_score(y_target, preds), 4))
- VADER를 이용한 감성분석
- SentimentIntensityAnalyzer 객체를 생성한 뒤에 문서별로 polarity_scores() 메서드를 호출해 감성점수를 구한다.
- 해당 문서의 감성 점수가 특정 임계값 이상이면 긍정, 그렇지 않으면 부정으로 판단함. (SentimentIntensityAnalyzer 객체의 polarity_scores() 메서드는 딕셔너리 형태의 감성점수 반환, compound가 neg,neu, pos score 를 적절히 조합해 -1에서 1 사이의 감성지수를 표현한 값임. Compound score 를 기반으로, 보통 0.1 이상이면 긍정 감성, 그 이하이면 부정 감성으로 판단)
def vader_polarity(review,threshold=0.1): #입력 파라미터로 영화 감상평 텍스트와, 긍정/부정을 결정하는 임계값을 가짐.
analyzer = SentimentIntensityAnalyzer()
scores = analyzer.polarity_scores(review) #감성결과 반환
# compound 값에 기반하여 threshold 입력값보다 크면 1, 그렇지 않으면 0을 반환
agg_score = scores['compound']
final_sentiment = 1 if agg_score >= threshold else 0
return final_sentiment
# apply lambda 식을 이용하여 레코드별로 vader_polarity( )를 수행하고 결과를 'vader_preds'에 저장
review_df['vader_preds'] = review_df['review'].apply( lambda x : vader_polarity(x, 0.1) ) #함수 호출하여 각 문서별로 감성결과를 새로운 칼럼으로 저장.
y_target = review_df['sentiment'].values
vader_preds = review_df['vader_preds'].values
print(confusion_matrix( y_target, vader_preds))
print("정확도:", np.round(accuracy_score(y_target , vader_preds),4))
print("정밀도:", np.round(precision_score(y_target , vader_preds),4))
print("재현율:", np.round(recall_score(y_target, vader_preds),4))
'Machine Learning > 텍스트 분석' 카테고리의 다른 글
[파이썬 머신러닝 가이드] 텍스트 분석 - 문서 군집화 (2) | 2023.12.26 |
---|---|
[파이썬 머신러닝 가이드] 텍스트 분석 - 토픽 모델링 (1) | 2023.12.26 |
[파이썬 머신러닝 가이드] 텍스트 분석 - 텍스트 분류 실습(20 뉴스그룹 분류) (2) | 2023.12.26 |
[파이썬 머신러닝 가이드] 텍스트 분석 - Bag of Words(BOW) (2) | 2023.12.26 |
[파이썬 머신러닝 가이드] 텍스트 분석 - 텍스트 전처리(정규화) (2) | 2023.12.26 |