본문 바로가기
국비 교육/머신러닝, 딥러닝

[텍스트 마이닝] 한글 텍스트 분석 - 한글 영화 감성분석

by 육츠 2024. 8. 1.
Contents 접기

필요한 패키지는 구글에... 다시 쳐봐야 할 것 같다..

Mecab 테스트

import MeCab
m = MeCab.Tagger()
m.parse('안녕하세요. 테스트 입니다.')
'안녕\tNNG,행위,T,안녕,*,*,*,*\n하\tXSV,*,F,하,*,*,*,*\n세요\tEP+EF,*,F,세요,Inflect,EP,EF,시/EP/*+어요/EF/*\n.\tSF,*,*,*,*,*,*,*\n테스트\tNNG,행위,F,테스트,*,*,*,*\n입니다\tVCP+EF,*,F,입니다,Inflect,VCP,EF,이/VCP/*+ᄇ니다/EF/*\n.\tSF,*,*,*,*,*,*,*\nEOS\n'

 

konlpy Mecab 테스트

konlpy는 한국어 자연어 처리를 위한 파이썬 라이브러리 중 하나로, 다양한 한국어 형태소 분석기를 제공한다.
한국어 형태소 분석을 수행하는 데 사용되며, 일반적으로 텍스트를 형태소 단위로 분해하여 명사, 동사, 형용사 등의 품사를 태깅한다.

from konlpy.tag import Mecab   # 소문자로 되어있음

tokenizer = Mecab(dicpath= 'c:/mecab/mecab-ko-dic/').morphs
print(tokenizer('안녕하세요. 테스트 입니다.'))
['안녕', '하', '세요', '.', '테스트', '입니다', '.']

 

[실습] 한글 영화 감성분석

데이터 로딩 및 확인

- 훈련데이터와 평가데이터가 나뉘어져 파일로 저장되어 있다.

import pandas as pd

train_df = pd.read_csv('./ratings_train.txt', sep='\t', encoding= 'utf-8')
train_df.head()

print(train_df.shape)
(150000, 3)

 

test_df = pd.read_csv('./ratings_test.txt', sep='\t', encoding= 'utf-8')
test_df.head()

print(test_df.shape)
(50000, 3)

 

긍정(1), 부정(0) 비율 확인

train_df['label'].value_counts()
label
0    75173
1    74827
Name: count, dtype: int64
test_df['label'].value_counts()
label
1    25173
0    24827
Name: count, dtype: int64

 

결측치 확인

train_df.isna().sum()
id          0
document    5
label       0
dtype: int64
test_df.isna().sum()
id          0
document    3
label       0
dtype: int64

 

데이터 전처리

결측치 삭제

train_df.dropna(inplace= True)
test_df.dropna(inplace= True)

 

id 컬럼 삭제

train_df.drop('id',axis = 1, inplace= True)
test_df.drop('id',axis = 1, inplace= True)

 

konlpy, Mecab 이용한 단어 토큰화

* mecab = Mecab('c:/mecab/mecab-ko-dic/') 경로 설정 해주어야 한다

from konlpy.tag import Mecab

mecab = Mecab('c:/mecab/mecab-ko-dic/')
tokens = [ mecab.morphs(sentence) for sentence in train_df['document']]

# 형태소 분석해서 단어 단위로 토큰한 것을 하나의 문장으로 다시 재결합
tokens = list(map(lambda x: ' '.join(x), tokens))
tokens[:10]
['아 더 빙 . . 진짜 짜증 나 네요 목소리',
 '흠 . .. 포스터 보고 초딩 영화 줄 . ... 오버 연기 조차 가볍 지 않 구나',
 '너무 재 밓었다그래서보는것을추천한다',
 '교도소 이야기 구먼 . . 솔직히 재미 는 없 다 . . 평점 조정',
 '사이몬페그 의 익살 스런 연기 가 돋보였 던 영화 ! 스파이더맨 에서 늙 어 보이 기 만 했 던 커스틴 던스트 가 너무나 도 이뻐 보였 다',
 '막 걸음마 뗀 3 세 부터 초등 학교 1 학년 생 인 8 살 용 영화 . ㅋㅋㅋ . .. 별반 개 도 아까움 .',
 '원작 의 긴장감 을 제대로 살려 내 지 못했 다 .',
 '별 반개 도 아깝 다 욕 나온다 이응경 길용우 연기 생활 이 몇 년 인지 . . 정말 발 로 해도 그것 보단 낫 겟 다 납치 . 감금 만 반복 반복 . . 이 드라마 는 가족 도 없 다 연기 못 하 는 사람 만 모엿 네',
 '액션 이 없 는데 도 재미 있 는 몇 안 되 는 영화',
 '왜 케 평점 이 낮 은 건데 ? 꽤 볼 만한데 . . 헐리우드 식 화려 함 에 만 너무 길들여져 있 나 ?']

 

KNU 한글 감성어 사진 로딩

SentiWordNet

감성 분석(긍정적인지 부정적인지 판단)을 수행하기 위한 자원 중 하나로,  WordNet은 단어들 간의 상위 및 하위어 관계를 나타내는 시맨틱 네트워크이며, SentiWordNet은 WordNet의 각 단어에 대해 긍정, 부정, 중립적인 정도를 나타내는 감성 점수를 부여한 자원

SentiWordNet의 감성 점수는 각 단어의 긍정성(Positive), 부정성(Negative), 중립성(Neutral)을 -1에서 1 사이의 실수 값으로 나타냅니다. 이 점수는 해당 단어가 가지는 감성적인 의미나 정도를 표현. 양수 값은 긍정적인 감성을 나타내며, 음수 값은 부정적인 감성을 나타냅니다. 0은 중립적인 감성을 나타냄

import json

with open('./SentiWord_info.json', encoding= 'utf-8', mode = 'r') as f:
    sentiword_info = json.load(f)

sentiword_dic = pd.DataFrame(sentiword_info)
print(sentiword_dic.shape)
print(sentiword_dic.head())
(14843, 3)
    word word_root polarity
0    (-;         (        1
1  (;_;)     (;_;)       -1
2   (^^)      (^^)        1
3  (^-^)     (^-^)        1
4   (^^*         (        1

 

sentiword_dic['polarity'] = sentiword_dic['polarity'].astype(int)
print('감성 최대값:', sentiword_dic['polarity'].max())
print('감성 최소값:', sentiword_dic['polarity'].min())
print('감성 평균값:', round(sentiword_dic['polarity'].mean(),3))
감성 최대값: 2
감성 최소값: -2
감성 평균값: -0.483

 

sentiword_dic['polarity'].value_counts()
polarity
-1    5029
-2    4797
 2    2597
 1    2266
 0     154
Name: count, dtype: int64

 

토큰 결과 (토큰화된 문장과 감정사전 비교)

sentiment_score = pd.DataFrame(columns=['review','sentimental_score'])

idx = 0
for token in tokens :
    senti_score = 0
    for i in range(len(sentiword_dic)):
        if sentiword_dic['word'][i] in token:  # 감상평 안에 포함되어 있으면
            senti_score += sentiword_dic['polarity'][i]
    sentiment_score.loc[idx] = [token, senti_score]
    idx += 1

오랜 시간이 소요되어 해당 결과를 교수님과 돌려 보지 못했음.
++ 프로젝트 기간 초반에 수업을 진행한 것이라 아직까지 오류 살펴 보지 못함

 

# 리뷰 감성값 데이터 프레임 저장
    # 저장되어있는 피클 파일을 불러와서 사용하면 됨 

import joblib  

joblib.dump(sentiment_score, './sentiment_score.pkl')  # 피클 파일
['./sentiment_score.pkl']
#불러오기
sentiment_score = joblib.load('./sentiment_score.pkl')

 

감성값 긍/부정 레이블 값으로 치환

sentiment_score['label'] = sentiment_score['sentiment_score'].map(lambda x : 1 if x >= 0 else 0 )
# map 함수를 거치면서 치환됨
    # 치환된 값을 가지고 혼동매트릭스

 

정답과 비교하여 정확도 측정

from sklearn.metrics import accuracy_score, confusion_matrix
cm = confusion_matrix(train_df['label'], sentiment_score['label'])
# 정답과 예측값
print(cm)

print(f'정확도: {accuracy_score(train_df['label'], sentiment_score['label']):.2f}')

 

추가 분석 사항

- 전처리
한글을 제외한 다른 문자 제거(이모티콘은 날아가겠지만, 감성지수에 초점을 맞춤) -> 제거 결과 아무런 값도 남지 않은 레코드 확인 -> 해당 레코드 삭제
불용어 제거: 한글 불용어 사전은 별도 구성 필요

- 분석
딥러닝의 LSTM 모형 사용 (문맥 기반으로 새로운 문서가 들어왔을때 긍정/부정을 판별)
별도의 감성 사전없이도 사용 가능