뉴스, 백과 사전 같은 텍스트는 객관적인 정보를 제공
비슷한 감정을 표현하는 문서는 유사한 단어 구성 및 언어적 특징을 보일 것을 가정
감정분석(Sentiment analysis)은 텍스트 내에 표현되는 감정 및 평가를 식별
모델링에서는 텍스트 내 (1)감정을 분류 하거나 (2)긍정/부정의 정도를 점수화
<모델 학습을 위한 데이터 분할>
:감정 모델을 직접 만들고 학습해보기!
학습 데이터 란 감정 분석 모델을 훈련시키기 위해 문장과 해당 문장의 감정이 포함되어 있는 데이터셋을 의미
from sklearn.model_selection import train_test_split
# 파일을 읽어오세요.
data = []
with open('emotions_train.txt', 'r') as f:
for line in f:
#각 세미 콜론을 기준으로 나눠져 있음
sent, emotion = line.rstrip().split(";")
data.append((sent, emotion)) #튜플 형태로 넣기
# 읽어온 파일을 학습 데이터와 평가 데이터로 분할하세요.
train, test = train_test_split(data, test_size = 0.2, random_state = 7)
# 학습 데이터셋의 문장과 감정을 분리하세요.
Xtrain = []
Ytrain = []
for train_data in train:
Xtrain.append(train_data[0]) #튜플의 첫번째 넣기
Ytrain.append(train_data[1]) #튜플의 두번째 넣기
print(len(Xtrain))
print(set(Ytrain))
# 평가 데이터셋의 문장과 감정을 분리하세요.
Xtest = []
Ytest = []
for test_data in test:
Xtest.append(test_data[0])
Ytest.append(test_data[1])
print(len(Xtest))
print(len(set(Ytest)))
나이브 베이즈
나이브 베이즈 기반 감정 분석은 주어진 텍스트가 특정 감정을 나타낼 확률을 예측하는 문제로 정의
P(감정|텍스트) = ? -> 조건부 확률 사용
베이즈 정리를 사용하여 텍스트의 감정 발생 확률을 추정
P(감정|텍스트) = P(텍스트|감정) X P(감정) / P(텍스트)
나이브(naive): 단순한, 순진한
텍스트 1의 감정 : 해당 감정 내 단어들이 발생할 가능성 X 감정의 발생 확률
감정의 발생 확률과 텍스트를 구성하는 단어들의 가능도(likelihood)로 텍스트의 감정 예측
단어의 가능도 : 단어의 빈도수로 추정
P(단어|감정) = 감정 내 단어의 빈도수 / 감정 내 모든 단어의 빈도수
Ex) P("재미있었어요" | 기쁨 ) = (기쁨을 표현하는 문서 내 "재미있었어요"의 빈도수) / (기쁨을 표현하는 문서 내 모든 단어의 빈도수)
감정의 발생 확률: 주어진 텍스트 데이터 내 해당 감정을 표현하는 문서의 비율로 추정
P(감정) = (해당 감정을 표현하는 문서의 수) / (데이터 내 모든 문서의 수)
텍스트의 감정별 확률값 중 최대 확률값을 나타내는 감정을 해당 문서의 감정으로 예측
ex) 기쁨, 분노 나타낼 확률을 따로 구해보면서!
<나이브 베이즈 학습>
----------------코드 넣기
나이브 베이즈 기반 감정 예측
스무딩(smoothing)
-> 학습 데이터 내 존재하지 않은 단어의 빈도 수를 보정
분자와 분모에 작은 수 더하기
소수단어의 감정별 가능도와 감정의 발생 확률은 모두 소수로 표현단어의 수가 많아질수록 텍스트의 확률값은 컴퓨터가 처리할 수 있는 소수점의 범위보다 작아질 수 있음--> 로그를 사용해서 계속해서 숫자가 작아지는 것을 방지 ( 로그 확률값의 합으로 텍스트의 감정 예측)
import pandas as pd
import numpy as np
def cal_partial_freq(texts, emotion):
partial_freq = dict()
filtered_texts = texts[texts['emotion'] == emotion]
filtered_texts = filtered_texts['sentence']
# 실습 2에서 구현한 부분을 완성하세요.
for sent in filtered_texts:
words = sent.rstrip().split()
for word in words:
if word not in partial_freq:
partial_freq[word] = 1
else:
partial_freq[word] += 1
return partial_freq
def cal_total_freq(partial_freq):
total = 0
# 실습 2에서 구현한 부분을 완성하세요.
for word,freq in partial_freq.items():
total += freq
return total
#전체 데이터: data
def cal_prior_prob(data, emotion):
filtered_texts = data[data['emotion'] == emotion] #특정 감정 나타내는 문장이 들어있음
# data 내 특정 감정의 로그발생 확률을 반환하는 부분을 구현하세요.
return np.log(len(filtered_texts)/len(data))
def predict_emotion(sent, data):
emotions = ['anger', 'love', 'sadness', 'fear', 'joy', 'surprise']
predictions = []
train_txt = pd.read_csv(data, delimiter=';', header=None, names=['sentence', 'emotion'])
# sent의 각 감정별 로그 확률을 predictions 리스트에 저장하세요.
for emotion in emotions:
#각 감정별 로그 확률 저장할 prob 정의
prob = 0
for word in sent.split():
emotion_counter = cal_partial_freq(train_txt, emotion)
prob += np.log((emotion_counter[word] + 10)/(cal_total_freq(emotion_counter) + 10))
prob += cal_prior_prob(train_txt, emotion)
predictions.append((emotion, prob))
predictions.sort(key = lambda a: a[1]) #lambda 함수를 사용해서 확률 기준으로 sorting!
return predictions[-1] #가장 큰 값은 가장 마지막 값
# 아래 문장의 예측된 감정을 확인하세요.
test_sent = "i really want to go and enjoy this party"
predicted = predict_emotion(test_sent, "emotions_train.txt")
print(predicted)
scikit-learn을 통한 나이브 베이즈 구현
scikit-learn은 각종 데이터 전처리 및 머신 러닝 모델을 간편한 형태로 제공하는 파이썬 라이브러리
CountVectorizer() 은 수치형 데이터로 바꿔줌
.fit_transform(doc) : 행렬 형태의 수치형 데이터로 변환됨.
--> 단어로 column 이 되어있음. column에 해당하는 단어의 빈도수를 계산.
.fit(학습데이터, 감정 label)
.transform(학습데이터) : 변환된 수치형으로 바꿔주기
.predict(변환한 것 넣어주기)
import pandas as pd
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
raw_text = pd.read_csv("emotions_train.txt", delimiter=';', header=None, names=['sentence','emotion'])
train_data = raw_text['sentence']
train_emotion = raw_text['emotion']
# CountVectorizer 객체인 변수 cv를 만들고, fit_transform 메소드로 train_data를 변환하세요.
cv = CountVectorizer()
transformed_text = cv.fit_transform(train_data)
# MultinomialNB 객체인 변수 clf를 만들고, fit 메소드로 지시사항 1번에서 변환된 train_data와 train_emotion을 학습하세요.
clf = MultinomialNB()
clf.fit(transformed_text, train_emotion)
# 아래 문장의 감정을 예측하세요.
test_data = ['i am curious', 'i feel gloomy and tired', 'i feel more creative', 'i feel a little mellow today']
doc_vector = cv.transform(test_data)
test_result = clf.predict(doc_vector)
print(test_result)
나이브 베이즈 기반 감정 분석 서비스
# 경고문을 무시합니다.
import warnings
warnings.filterwarnings(action='ignore')
from flask import Flask, request, jsonify
import pickle
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
json_ = request.json
query = json_['infer_texts']
# 학습된 객체 cv 변수와 clf 변수를 이용해 전달된 문자열의 감정을 예측하는 코드를 작성하세요.
prediction = clf.predict(cv.transform(query))
# 예측된 결과를 resredict 메소드를 사용할 ponse 딕셔너리에 "문서의 순서: 예측된 감점" 형태로 저장하세요.
response = dict()
for idx, pred in enumerate(prediction):
response[idx] = pred #enumerate사용하면 index값이 부여됨
return jsonify(response)
if __name__ == '__main__':
with open('nb_model.pkl', 'rb') as f:
cv, clf = pickle.load(f)
app.run(host='0.0.0.0', port=8080)
기타 감정 분석 서비스
감정 분석: 지도학습(supervised learning)기반의 분류 및 예측의 문제
--> 답안: 감정의 label이 존재해야 함!
임베딩 벡터를 사용하여 머신러닝 알고리즘 적용이 가능
1. 단어 임베딩 벡터의 평균을 사용(가장 간단한 방법)
2. 단어 임베딩 벡터에 필터를 적용하여 CNN 기반으로 감정 분류(문자 임베딩 벡터 필터 적용도 가능)
3. LSTM,GRU를 활용하여 RNN기반으로 분류 및 예측
'Data Analysis' 카테고리의 다른 글
문서 유사도 및 언어 모델 (0) | 2022.07.29 |
---|---|
한국어 자연어 처리 및 문장 유사도 (0) | 2022.07.29 |
텍스트 전처리 및 단어 임베딩 (0) | 2022.07.26 |