감성분석 방법

 

셋팅

from google.colab import drive
drive.mount('/content/gdrive')

#형태소 분석기 설치
!apt-get update
!apt-get install g++ openjdk-8-jdk
!pip install JPype1
!pip install rhinoMorph

 

데이터 읽기, 쓰기 함수 

def read_data(filename, encoding='cp949'): # 읽기 함수 정의
  with open(filename, 'r', encoding=encoding) as f:
    data = [line.split('\t') for line in f.read().splitlines()]
    data = data[1:] # txt 파일의 헤더(id document label)는 제외하기
  return data

def write_data(data, filename, encoding='cp949'): # 쓰기 함수도 정의
  with open(filename, 'w', encoding=encoding) as f:
    f.write(data)
data = read_data('/content/gdrive/My Drive/pytest/ratings.txt', encoding='cp949')
#data = read_data('ratings.txt', encoding='cp949')

 

형태소 분석

import rhinoMorph
rn = rhinoMorph.startRhino()

morphed_data = ''
for data_each in data:
  morphed_data_each = rhinoMorph.onlyMorph_list(rn, data_each[1],
    pos=['NNG', 'NNP', 'VV', 'VA', 'XR', 'IC', 'MM', 'MAG', 'MAJ'])
  joined_data_each = ' '.join(morphed_data_each)    # 문자열을 하나로 연결
  if joined_data_each:                              # 내용이 있는 경우만 저장하게 함
    morphed_data += data_each[0]+"\t"+joined_data_each+"\t"+data_each[2]+"\n"

# 형태소 분석된 파일 저장
write_data(morphed_data, 'ratings_morphed.txt', encoding='cp949')

 

감정 사전 읽기

# 감정사전 읽기
data_id = [line[0] for line in data]    # 데이터 id
data_text = [line[1] for line in data]  # 데이터 본문
data_senti = [line[2] for line in data] # 데이터 긍부정 부분

# 각 줄에 하나의 원소씩 있는데, 리스트 하나에 저장됨
positive = read_data('/content/gdrive/My Drive/pytest/positive.txt') # 긍정 감정사전 읽기
negative = read_data('/content/gdrive/My Drive/pytest/negative.txt') # 부정 감정사전 읽기

print("positive : ",positive)
print("negative : ", negative)

pos_found = []
neg_found = []

 

감정 단어 파악

#하나의 단어를 쪼개서, 그 단어가 있는지 없는 지 파악하게 해준다. 
def cntWordInLine(data, senti):
  senti_found = []
  for onedata in data:
    oneline_word = onedata.split(' ') # 한 줄의 데이터를 공백 단위로 분리하여 리스트로 저장
    senti_temp = 0 # 그 줄에서 발견된 감정단어의 수를 담는 변수
    for sentiword in senti: # 감정사전의 어휘
      
      # 단어가 발견됐는지 안 됐는지만 보기만 하겠다
      if sentiword[0] in oneline_word: # sentiword[0] 하여 리스트 원소를 문자열로 추출
        senti_temp += 1 # 현재의 감정단어와 일치하면 숫자를 하나 올려 줌 (중복X)
    
    senti_found.append(senti_temp) # 현재의 줄에서 찾은 감성단어의 숫자를 해당 위치에 저장
  return senti_found

data_senti_poscnt = cntWordInLine(data_text, positive)
data_senti_negcnt = cntWordInLine(data_text, negative)

print(data_senti_poscnt[:20])
print(data_senti_negcnt[:20])

[5, 1, 0, 0, 2, 1, 0, 0, 0, 1, 1, 1, 0, 1, 2, 0, 1, 0, 1, 0]
[1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1]

 

감정 점수 계산

# pandas 데이터프레임 저장
import pandas as pd
newdata = pd.DataFrame({'id':data_id, 'text':data_text, 'original':data_senti,
                        'pos':data_senti_poscnt, 'neg': data_senti_negcnt})
senti_score = newdata['pos']-newdata['neg']		#금정 개수 - 부정개수
newdata['senti_score'] = senti_score

newdata.loc[newdata.senti_score > 0, 'new'] = 1
# 정답의 데이터가 중립이 없어서 0도 포함
newdata.loc[newdata.senti_score <= 0, 'new'] = 0


# 처음에 기록된 긍부정과 새로 계산된 긍부정 같은지 여부 저장 ( matched 열에)
# to_numeric으로 문자를 숫자로 변환해서 보기
newdata.loc[pd.to_numeric(newdata.original) == newdata.new, 'matched'] = 'True'
newdata.loc[pd.to_numeric(newdata.original) != newdata.new, 'matched'] = 'False'
  • 긍정 개수- 부정개수 빼서 senti_score에 저장함
  • 처음 기록된 긍부정과 새로운 결과랑 비교해서 matched 열에 저장함

 

원 점수와 비교 및 저장

# 벡터 연산 : 같은 위치에 있는 것끼리 같은 연산을 수행
score = newdata.matched.str.count('True').sum() / (newdata.matched.str.count('True').sum()
+ newdata.matched.str.count('False').sum()) * 100
print(score)
newdata.to_csv('newfile.csv', sep=',', encoding='cp949', index=False) # csv 저장
newdata.to_csv('newfile2.txt', sep='\t', encoding='cp949'
, index=False) # 또는 txt 저장

 

 

시그모이드 점수 계산

  • 시그모이드란
    • 모든 값을 0-1로 바꿔줌
    • 정규화하는 효과를 가짐
# 시그모이드 점수 계산
import math
def sigmoid(x):
  return 1 / (1 + math.exp(-x))
newdata['sigmoid'] = newdata.senti_score.apply(sigmoid)

 

 

 

+ Recent posts