[데이터] 감성분석

오찬주·2024년 11월 9일
post-thumbnail

이제 드디어 코드를 짤 차례다 !!!
우리에게는 다운받은 mecab과 감성 분석을 할 엑셀 파일이 준비되어있다.

데이터 불러오기

엑셀 파일로 저장된 데이터가 잘 불러와지는지, 경로가 맞는지 확인해보자.

import pandas as pd

# 파일 경로
file_path = '/Users/ohchanju/Desktop/data/housing.xlsx'

# 데이터 불러오기
df = pd.read_excel(file_path)

# 데이터 확인
print(df.head())

내 경로는 저렇게 되어있다.

💡 만약 경로를 모르겠다면?, 파일 우클릭 후 정보 가져오기를 누르고 위치를 복붙해주자! (맥북 🍎)

코드를 실행하면 이렇게 잘 뜨는걸 확인할 수 있다!


mecab을 사용해 형태소 분리

형태소 분리기 mecab을 사용하게 된다면 결과가 2차원 리스트로 저장이 된다. 따라서 이를 하나씩 감성 분석을 해주기 위해 1차원으로 바꿔줘야 한다.

나는 엑셀 데이터 프레임에서 본문 열을 감성 분석해줄 것이기에 본문 열을 선택해준다. 역시나 내가 잘 선택했는지 확인해준다.

# '본문' 열 선택
texts = df['본문'] 

texts.head()

결과는 다음과 같다.

잘 불러와지는걸 확인했으니 mecab으로 형태소 분리를 해주자. 이어서 1차원 배열로 바꾸어 준다.

from konlpy.tag import Mecab

mecab = Mecab()

# 비어 있거나 문자열이 아닌 항목을 건너뛰도록 예외 처리 추가
tokens = [mecab.morphs(word) for word in texts if isinstance(word, str) and word.strip()]

# 1차원 배열로 변경
tokens = list(map(lambda x: " ".join(x), tokens))

# 우선 10개의 행만 가져와서 잘 되는지 확인
print(tokens[:10])

💡 2차원 배열 -> 1차원 배열 코드를 더 자세히 살펴보자!

tokens = list(map(lambda x: " ".join(x), tokens))

더 위의 코드에서 tokens를 mecab을 이용해 형태소 분리를 해주었고, 2차원 배열로 저장되어있었다.
이 tokens를 다시 1차원 배열로 저장하는 코드다.
각 요소는 형태소 리스트로 되어있었기에 map() 함수를 사용해 각 리스트를 공백으로 합친 문자열로 변환해준다.

이후 익명함수join()함수를 사용해
lambda x: " ".join(x) 이런식으로 리스트 x를 공백으로 연결된 문자열로 바꾼 것이다.


KNU 감성 사전 불러오기

import pandas as pd
import json
from konlpy.tag import Mecab

# KNU 감성어 사전 파일 불러오기
sentiment_file_path = '/Users/ohchanju/Desktop/KnuSentiLex/data/SentiWord_info.json'

# JSON 파일 열기 (knu 감성어 사전 파일은 json 파일 형식임)
with open(sentiment_file_path, encoding='utf-8-sig', mode='r') as f: 
    SentiWord_info = json.load(f)

# 데이터프레임으로 변환
sentiword_dic = pd.DataFrame(SentiWord_info)

# 데이터 확인
print(sentiword_dic.head())

KNU 감성어 사전은 json 파일로 만들어져 있기에 json 라이브러리를 호출해 사전 파일 SentiWord_info.json을 연다.

기사 본문과 비교할 수 있도록 하기 위해 감성 사전을 데이터 프레임으로 변경해준다. 결과는 다음과 같다.

감성 분석

이제 기사 본문 데이터 프레임과 감성 사전 데이터 프레임을 하나씩 비교해서 감성 점수를 나타낸다.

import pandas as pd

# 기사별 점수를 저장하기 위한 데이터 프레임 생성
df = pd.DataFrame(columns=("texts", "sentiment"))

# 다음 기사로 넘기기 위해 초기값 설정
idx = 0

# 전체 기사에서 기사 하나씩 가져옴
for token in tokens:
    sentiment=0
    for i in range(0, len(sentiword_dic)):
        if sentiword_dic.word[i] in token:
            sentiment += int(sentiword_dic.polarity[i])
    df.loc[idx] = [token, sentiment]
    idx += 1    

print(df)

그럼 결과가 이렇게 나온다.

만약 엑셀 파일로 받아보고 싶으면 다음 코드를 추가해주면 된다.

df.to_excel("article_sentiments.xlsx", index=False, encoding='utf-8-sig')

# 잘 저장되었는지 확인용
print("엑셀 파일 저장 완료 ~~)

그럼 결과값이 현재 작업 중인 디렉토리에 생성된다. 만약 특정 경로에 저장해주고 싶다면, 파일명 앞에 경로를 같이 작성해주면 된다. (/User/ohchanju/Desktop/data/~~ 이런식으로)


감성 점수 평균

나는 키워드별 엑셀파일들이 각각 존재했고, 그 키워드에 대한 기사 전체의 감성 점수를 알고 싶었기에 평균 낼 필요가 있었다. 이를 구하는 코드는 다음과 같다.

# 긍정적 감성과 부정적 감성을 계산
total_positive = df[df['sentiment'] > 0]['sentiment'].sum()  
total_negative = df[df['sentiment'] < 0]['sentiment'].sum() 

# 결과 출력
print(f"전체 긍정 점수: {total_positive}")
print(f"전체 부정 점수: {total_negative}")

# 전체 감성 점수 계산
total_sentiment_score = total_positive + total_negative
print(f"전체 감성 점수: {total_sentiment_score}")

다음 글에서는 감성 분석 시각화에 대해 다루어 보겠다 !

profile
프론트엔드 엔지니어를 희망합니다 :-)

0개의 댓글