Skip to content
Home » 감성 분석 파이썬 | 감정 분석 Sentiment Analysis 20 개의 가장 정확한 답변

감성 분석 파이썬 | 감정 분석 Sentiment Analysis 20 개의 가장 정확한 답변

당신은 주제를 찾고 있습니까 “감성 분석 파이썬 – 감정 분석 Sentiment Analysis“? 다음 카테고리의 웹사이트 https://kk.taphoamini.com 에서 귀하의 모든 질문에 답변해 드립니다: https://kk.taphoamini.com/wiki/. 바로 아래에서 답을 찾을 수 있습니다. 작성자 이수안컴퓨터연구소 이(가) 작성한 기사에는 조회수 6,561회 및 좋아요 123개 개의 좋아요가 있습니다.

감성 분석 파이썬 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 감정 분석 Sentiment Analysis – 감성 분석 파이썬 주제에 대한 세부정보를 참조하세요

자연어 처리 Natural Language Processing
감정 분석 Sentiment Analysis
감정 사전, afinn, 뉴스그룹 데이터, 네이버 영화 리뷰, 네이버 쇼핑 데이터
Colab: https://colab.research.google.com/drive/1CFBtnM5W7bGOp0SVhZeHymb78dMgeSBu?usp=sharing
이수안 컴퓨터 연구소 (SuanLab)
www.suanlab.com

감성 분석 파이썬 주제에 대한 자세한 내용은 여기를 참조하세요.

6) 네이버 영화 리뷰 감성 분류하기(Naver Movie Review …

Okt는 위와 같이 KoNLPy에서 제공하는 형태소 분석기입니다. 한국어을 토큰화할 때는 영어처럼 띄어쓰기 기준으로 토큰화를 하는 것이 아니라, 주로 형태소 분석기를 사용 …

+ 여기에 표시

Source: wikidocs.net

Date Published: 11/19/2022

View: 3438

[python/NLP] 감정분류(한국어)- 리뷰데이터 학습, 평가, 예측까지

그 후 DATA 라는 폴더를 만들어 그 안에 파일들이 위치하도록 해줍니다. 데이터 분석하기. 감정분류에 사용할 데이터가 어떻게 이루어져있는지 살펴보도록 …

+ 여기를 클릭

Source: wonhwa.tistory.com

Date Published: 3/14/2022

View: 2017

[Python] 소셜 데이터의 감성 예측 – velog

학습 내용 · 모듈 설치 · 파이썬 3.8이하 (중요) · 핵심 개념 · 단어 표현의 카테고리화 · 카운트 기반 벡터화 · TF-IDF 기반 벡터화 · 감성 분석(오피니언 …

+ 여기에 더 보기

Source: velog.io

Date Published: 3/5/2022

View: 6204

[파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2

감성 분석(Sentiment Analysis)은 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법으로 소셜 미디어, 여론조사, 온라인 리뷰, …

+ 자세한 내용은 여기를 클릭하십시오

Source: rahites.tistory.com

Date Published: 1/1/2022

View: 1523

[Python] 뉴스 감성지수 분류 모델 – sieon – 티스토리

Test Set의 정확도 역시 0.91로 높은 성능을 보이고 있습니다. 이후 이 모델을 웹 서버에 Deploy 하여 네이버 News API를 통해 수집한 뉴스들을 분석하는 …

+ 여기에 표시

Source: sieon-dev.tistory.com

Date Published: 9/14/2021

View: 9842

감정 분석(Sentiment Analysis) – Google Colab

파이썬으로 감정 분석하는 방법은 크게 두 가지로 구분. 감정 어휘 사전을 이용한 감정 상태 분류. 미리 분류해둔 감정어 사전을 통해 분석하고자 하는 텍스트의 단어 …

+ 여기에 자세히 보기

Source: colab.research.google.com

Date Published: 5/15/2022

View: 6581

[파이썬] 네이버 클로바 Sentiment 문장 텍스트 감정 분석

[파이썬] 네이버 클로바 Sentiment 문장 텍스트 감정 분석 … 바빠서 시간이 부족하거나 파이썬 코딩이 처음인 사람들이 많다. 누구나 손쉽게 코딩을 …

+ 여기에 더 보기

Source: dataanalytics.tistory.com

Date Published: 3/2/2021

View: 1534

감성분석 준비 :: 감성분석과 문서분류 – 마인드스케일

감성분석이란 문서에 나타난 긍부정의 감정 또는 태도를 분석하는 것입니다. 감정 분석에는 크게 사전에 의한 방법과 기계 학습에 의한 방법 2가지가 있습니다.

+ 여기에 표시

Source: mindscale.kr

Date Published: 6/6/2022

View: 2126

주제와 관련된 이미지 감성 분석 파이썬

주제와 관련된 더 많은 사진을 참조하십시오 감정 분석 Sentiment Analysis. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

감정 분석 Sentiment Analysis
감정 분석 Sentiment Analysis

주제에 대한 기사 평가 감성 분석 파이썬

  • Author: 이수안컴퓨터연구소
  • Views: 조회수 6,561회
  • Likes: 좋아요 123개
  • Date Published: 2021. 3. 17.
  • Video Url link: https://www.youtube.com/watch?v=7GUoDHxN5NM

6) 네이버 영화 리뷰 감성 분류하기(Naver Movie Review Sentiment Analysis)

이번에 사용할 데이터는 네이버 영화 리뷰 데이터입니다. 총 200,000개 리뷰로 구성된 데이터로 영화 리뷰에 대한 텍스트와 해당 리뷰가 긍정인 경우 1, 부정인 경우 0을 표시한 레이블로 구성되어져 있습니다. 해당 데이터를 다운로드 받아 감성 분류를 수행하는 모델을 만들어보겠습니다.

1. 네이버 영화 리뷰 데이터에 대한 이해와 전처리

데이터 다운로드 링크 : https://github.com/e9t/nsmc/

import pandas as pd import numpy as np import matplotlib.pyplot as plt import re import urllib.request from konlpy.tag import Okt from tqdm import tqdm from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences

1) 데이터 로드하기

위 링크로부터 훈련 데이터에 해당하는 ratings_train.txt와 테스트 데이터에 해당하는 ratings_test.txt를 다운로드합니다.

urllib.request.urlretrieve(“https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt”, filename=”ratings_train.txt”) urllib.request.urlretrieve(“https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt”, filename=”ratings_test.txt”)

pandas를 이용하여 훈련 데이터는 train_data에 테스트 데이터는 test_data에 저장합니다.

train_data = pd.read_table(‘ratings_train.txt’) test_data = pd.read_table(‘ratings_test.txt’)

train_data에 존재하는 영화 리뷰의 개수를 확인해봅시다.

print(‘훈련용 리뷰 개수 :’,len(train_data)) # 훈련용 리뷰 개수 출력

훈련용 리뷰 개수 : 150000

train_data는 총 150,000개의 리뷰가 존재합니다. 상위 5개의 샘플을 출력해봅시다.

train_data[:5] # 상위 5개 출력

해당 데이터는 id, document, label 총 3개의 열로 구성되어져 있습니다. id는 감성 분류를 수행하는데 도움이 되지 않으므로 앞으로 무시합니다. 결국 이 모델은 리뷰 내용을 담고있는 document와 해당 리뷰가 긍정(1), 부정(0)인지를 나타내는 label 두 개의 열을 학습하는 모델이 되어야 합니다.

또한 단지 상위 5개의 샘플만 출력해보았지만 한국어 데이터와 영어 데이터의 차이를 확인할 수 있습니다. 예를 들어, 인덱스 2번 샘플은 띄어쓰기를 하지 않아도 글을 쉽게 이해할 수 있는 한국어의 특성으로 인해 띄어쓰기가 되어있지 않습니다. test_data의 리뷰 개수와 상위 5개의 샘플을 확인해봅시다.

print(‘테스트용 리뷰 개수 :’,len(test_data)) # 테스트용 리뷰 개수 출력

테스트용 리뷰 개수 : 50000

test_data는 총 50,000개의 영화 리뷰가 존재합니다. 상위 5개의 샘플을 출력해봅시다.

test_data[:5]

test_data도 train_data와 동일한 형식으로 id, document, label 3개의 열로 구성되어져 있습니다.

2) 데이터 정제하기

train_data의 데이터 중복 유무를 확인합니다.

# document 열과 label 열의 중복을 제외한 값의 개수 train_data[‘document’].nunique(), train_data[‘label’].nunique()

(146182, 2)

총 150,000개의 샘플이 존재하는데 document열에서 중복을 제거한 샘플의 개수가 146,182개라는 것은 약 4,000개의 중복 샘플이 존재한다는 의미입니다. label 열은 0 또는 1의 두 가지 값만을 가지므로 2가 출력됩니다. 중복 샘플을 제거합니다.

# document 열의 중복 제거 train_data.drop_duplicates(subset=[‘document’], inplace=True)

중복 샘플을 제거하였습니다. 중복이 제거되었는지 전체 샘플 수를 확인합니다.

print(‘총 샘플의 수 :’,len(train_data))

총 샘플의 수 : 146183

중복 샘플이 제거되었습니다. train_data에서 해당 리뷰의 긍, 부정 유무가 기재되어있는 레이블(label) 값의 분포를 보겠습니다.

train_data[‘label’].value_counts().plot(kind = ‘bar’)

앞서 확인하였듯이 약 146,000개의 영화 리뷰 샘플이 존재하는데 그래프 상으로 긍정과 부정 둘 다 약 72,000개의 샘플이 존재하여 레이블의 분포가 균일한 것처럼 보입니다. 정확하게 몇 개인지 확인해봅시다.

print(train_data.groupby(‘label’).size().reset_index(name = ‘count’))

label count 0 0 73342 1 1 72841

레이블이 0인 리뷰가 근소하게 많습니다. 리뷰 중에 Null 값을 가진 샘플이 있는지 확인합니다.

print(train_data.isnull().values.any())

True

True가 나왔다면 데이터 중에 Null 값을 가진 샘플이 존재한다는 의미입니다. 어떤 열에 존재하는지 확인해봅시다.

print(train_data.isnull().sum())

id 0 document 1 label 0 dtype: int64

리뷰가 적혀있는 document 열에서 Null 값을 가진 샘플이 총 1개가 존재한다고 합니다. 그렇다면 document 열에서 Null 값이 존재한다는 것을 조건으로 Null 값을 가진 샘플이 어느 인덱스의 위치에 존재하는지 한 번 출력해봅시다.

train_data.loc[train_data.document.isnull()]

출력 결과는 위와 같습니다. Null 값을 가진 샘플을 제거하겠습니다.

train_data = train_data.dropna(how = ‘any’) # Null 값이 존재하는 행 제거 print(train_data.isnull().values.any()) # Null 값이 존재하는지 확인

False

Null 값을 가진 샘플이 제거되었습니다. 다시 샘플의 개수를 출력하여 1개의 샘플이 제거되었는지 확인해봅시다.

print(len(train_data))

146182

데이터의 전처리를 수행해보겠습니다. 위의 train_data와 test_data에서 온점(.)이나 ?와 같은 각종 특수문자가 사용된 것을 확인했습니다. train_data로부터 한글만 남기고 제거하기 위해서 정규 표현식을 사용해보겠습니다.

우선 영어를 예시로 정규 표현식을 설명해보겠습니다. 영어의 알파벳들을 나타내는 정규 표현식은 [a-zA-Z]입니다. 이 정규 표현식은 영어의 소문자와 대문자들을 모두 포함하고 있는 정규 표현식으로 이를 응용하면 영어에 속하지 않는 구두점이나 특수문자를 제거할 수 있습니다. 예를 들어 알파벳과 공백을 제외하고 모두 제거하는 전처리를 수행하는 예제는 다음과 같습니다.

#알파벳과 공백을 제외하고 모두 제거 eng_text = ‘do!!! you expect… people~ to~ read~ the FAQ, etc. and actually accept hard~! atheism?@@’ print(re.sub(r'[^a-zA-Z ]’, ”, eng_text))

‘do you expect people to read the FAQ etc and actually accept hard atheism’

위와 같은 원리를 한국어 데이터에 적용하고 싶다면, 우선 한글을 범위 지정할 수 있는 정규 표현식을 찾아내면 되겠습니다. 우선 자음과 모음에 대한 범위를 지정해보겠습니다. 일반적으로 자음의 범위는 ㄱ ~ ㅎ, 모음의 범위는 ㅏ ~ ㅣ와 같이 지정할 수 있습니다. 해당 범위 내에 어떤 자음과 모음이 속하는지 알고 싶다면 아래의 링크를 참고하시기 바랍니다.

링크 : https://www.unicode.org/charts/PDF/U3130.pdf

ㄱ ~ ㅎ: 3131 ~ 314E

ㅏ ~ ㅣ: 314F ~ 3163

완성형 한글의 범위는 가 ~ 힣과 같이 사용합니다. 해당 범위 내에 포함된 음절들은 아래의 링크에서 확인할 수 있습니다.

링크 : https://www.unicode.org/charts/PDF/UAC00.pdf

위 범위 지정을 모두 반영하여 train_data에 한글과 공백을 제외하고 모두 제거하는 정규 표현식을 수행해봅시다.

# 한글과 공백을 제외하고 모두 제거 train_data[‘document’] = train_data[‘document’].str.replace(“[^ㄱ-ㅎㅏ-ㅣ가-힣 ]”,””) train_data[:5]

상위 5개의 샘플을 다시 출력해보았는데, 정규 표현식을 수행하자 기존의 공백. 즉, 띄어쓰기는 유지되면서 온점과 같은 구두점 등은 제거되었습니다. 사실 네이버 영화 리뷰는 한글이 아니더라도 영어, 숫자, 특수문자로도 리뷰를 업로드할 수 있습니다. 다시 말해 기존에 한글이 없는 리뷰였다면 더 이상 아무런 값도 없는 빈(empty) 값이 되었을 것입니다. train_data에 공백(whitespace)만 있거나 빈 값을 가진 행이 있다면 Null 값으로 변경하도록 하고, Null 값이 존재하는지 확인해보겠습니다.

train_data[‘document’] = train_data[‘document’].str.replace(‘^ +’, “”) # white space 데이터를 empty value로 변경 train_data[‘document’].replace(”, np.nan, inplace=True) print(train_data.isnull().sum())

id 0 document 789 label 0 dtype: int64

Null 값이 789개나 새로 생겼습니다. Null 값이 있는 행을 5개만 출력해볼까요?

train_data.loc[train_data.document.isnull()][:5]

Null 샘플들은 레이블이 긍정일 수도 있고, 부정일 수도 있습니다. 아무런 의미도 없는 데이터므로 제거해줍니다.

train_data = train_data.dropna(how = ‘any’) print(len(train_data))

145393

샘플 개수가 또 다시 줄어서 145,393개가 남았습니다. 테스트 데이터에 앞서 진행한 전처리 과정을 동일하게 진행합니다.

test_data.drop_duplicates(subset = [‘document’], inplace=True) # document 열에서 중복인 내용이 있다면 중복 제거 test_data[‘document’] = test_data[‘document’].str.replace(“[^ㄱ-ㅎㅏ-ㅣ가-힣 ]”,””) # 정규 표현식 수행 test_data[‘document’] = test_data[‘document’].str.replace(‘^ +’, “”) # 공백은 empty 값으로 변경 test_data[‘document’].replace(”, np.nan, inplace=True) # 공백은 Null 값으로 변경 test_data = test_data.dropna(how=’any’) # Null 값 제거 print(‘전처리 후 테스트용 샘플의 개수 :’,len(test_data))

전처리 후 테스트용 샘플의 개수 : 48852

3) 토큰화

토큰화를 진행해봅시다. 토큰화 과정에서 불용어를 제거하겠습니다. 불용어는 정의하기 나름인데, 한국어의 조사, 접속사 등의 보편적인 불용어를 사용할 수도 있겠지만 결국 풀고자 하는 문제의 데이터를 지속 검토하면서 계속해서 추가하는 경우 또한 많습니다. 실제 현업인 상황이라면 일반적으로 아래의 불용어보다 더 많은 불용어를 사용할 수 있습니다.

stopwords = [‘의’,’가’,’이’,’은’,’들’,’는’,’좀’,’잘’,’걍’,’과’,’도’,’를’,’으로’,’자’,’에’,’와’,’한’,’하다’]

여기서는 위 정도로만 불용어를 정의하고, 토큰화를 위한 형태소 분석기는 KoNLPy의 Okt를 사용합니다. Okt를 복습해봅시다.

okt = Okt() okt.morphs(‘와 이런 것도 영화라고 차라리 뮤직비디오를 만드는 게 나을 뻔’, stem = True)

[‘오다’, ‘이렇다’, ‘것’, ‘도’, ‘영화’, ‘라고’, ‘차라리’, ‘뮤직비디오’, ‘를’, ‘만들다’, ‘게’, ‘나다’, ‘뻔’]

Okt는 위와 같이 KoNLPy에서 제공하는 형태소 분석기입니다. 한국어을 토큰화할 때는 영어처럼 띄어쓰기 기준으로 토큰화를 하는 것이 아니라, 주로 형태소 분석기를 사용한다고 언급한 바 있습니다. stem = True를 사용하면 일정 수준의 정규화를 수행해주는데, 예를 들어 위의 예제의 결과를 보면 ‘이런’이 ‘이렇다’로 변환되었고 ‘만드는’이 ‘만들다’로 변환된 것을 알 수 있습니다. train_data에 형태소 분석기를 사용하여 토큰화를 하면서 불용어를 제거하여 X_train에 저장합니다.

X_train = [] for sentence in tqdm(train_data[‘document’]): tokenized_sentence = okt.morphs(sentence, stem=True) # 토큰화 stopwords_removed_sentence = [word for word in tokenized_sentence if not word in stopwords] # 불용어 제거 X_train.append(stopwords_removed_sentence)

상위 3개의 샘플만 출력하여 결과를 확인해봅시다.

print(X_train[:3])

[[‘아’, ‘더빙’, ‘진짜’, ‘짜증나다’, ‘목소리’], [‘흠’, ‘포스터’, ‘보고’, ‘초딩’, ‘영화’, ‘줄’, ‘오버’, ‘연기’, ‘조차’, ‘가볍다’, ‘않다’], [‘너’, ‘무재’, ‘밓었’, ‘다그’, ‘래서’, ‘보다’, ‘추천’, ‘다’]]

형태소 토큰화가 진행된 것을 볼 수 있습니다. 테스트 데이터에 대해서도 동일하게 토큰화를 해줍니다.

X_test = [] for sentence in tqdm(test_data[‘document’]): tokenized_sentence = okt.morphs(sentence, stem=True) # 토큰화 stopwords_removed_sentence = [word for word in tokenized_sentence if not word in stopwords] # 불용어 제거 X_test.append(stopwords_removed_sentence)

지금까지 훈련 데이터와 테스트 데이터에 대해서 텍스트 전처리를 진행해보았습니다.

4) 정수 인코딩

기계가 텍스트를 숫자로 처리할 수 있도록 훈련 데이터와 테스트 데이터에 정수 인코딩을 수행해야 합니다. 우선, 훈련 데이터에 대해서 단어 집합(vocaburary)을 만들어봅시다.

tokenizer = Tokenizer() tokenizer.fit_on_texts(X_train)

단어 집합이 생성되는 동시에 각 단어에 고유한 정수가 부여되었습니다. 이는 tokenizer.word_index를 출력하여 확인 가능합니다.

print(tokenizer.word_index)

{‘영화’: 1, ‘보다’: 2, ‘을’: 3, ‘없다’: 4, ‘이다’: 5, ‘있다’: 6, ‘좋다’: 7, … 중략 … ‘디케이드’: 43751, ‘수간’: 43752}

단어가 43,000개가 넘게 존재합니다. 각 정수는 전체 훈련 데이터에서 등장 빈도수가 높은 순서대로 부여되었기 때문에, 높은 정수가 부여된 단어들은 등장 빈도수가 매우 낮다는 것을 의미합니다. 여기서는 빈도수가 낮은 단어들은 자연어 처리에서 배제하고자 합니다. 등장 빈도수가 3회 미만인 단어들이 이 데이터에서 얼만큼의 비중을 차지하는지 확인해봅시다.

threshold = 3 total_cnt = len(tokenizer.word_index) # 단어의 수 rare_cnt = 0 # 등장 빈도수가 threshold보다 작은 단어의 개수를 카운트 total_freq = 0 # 훈련 데이터의 전체 단어 빈도수 총 합 rare_freq = 0 # 등장 빈도수가 threshold보다 작은 단어의 등장 빈도수의 총 합 # 단어와 빈도수의 쌍(pair)을 key와 value로 받는다. for key, value in tokenizer.word_counts.items(): total_freq = total_freq + value # 단어의 등장 빈도수가 threshold보다 작으면 if(value < threshold): rare_cnt = rare_cnt + 1 rare_freq = rare_freq + value print('단어 집합(vocabulary)의 크기 :',total_cnt) print('등장 빈도가 %s번 이하인 희귀 단어의 수: %s'%(threshold - 1, rare_cnt)) print("단어 집합에서 희귀 단어의 비율:", (rare_cnt / total_cnt)*100) print("전체 등장 빈도에서 희귀 단어 등장 빈도 비율:", (rare_freq / total_freq)*100) 단어 집합(vocabulary)의 크기 : 43752 등장 빈도가 2번 이하인 희귀 단어의 수: 24337 단어 집합에서 희귀 단어의 비율: 55.62488571950996 전체 등장 빈도에서 희귀 단어 등장 빈도 비율: 1.8715872104872904 등장 빈도가 threshold 값인 3회 미만. 즉, 2회 이하인 단어들은 단어 집합에서 무려 절반 이상을 차지합니다. 하지만, 실제로 훈련 데이터에서 등장 빈도로 차지하는 비중은 상대적으로 매우 적은 수치인 1.87%밖에 되지 않습니다. 아무래도 등장 빈도가 2회 이하인 단어들은 자연어 처리에서 별로 중요하지 않을 듯 합니다. 그래서 이 단어들은 정수 인코딩 과정에서 배제시키겠습니다. 등장 빈도수가 2이하인 단어들의 수를 제외한 단어의 개수를 단어 집합의 최대 크기로 제한하겠습니다. # 전체 단어 개수 중 빈도수 2이하인 단어는 제거. # 0번 패딩 토큰을 고려하여 + 1 vocab_size = total_cnt - rare_cnt + 1 print('단어 집합의 크기 :',vocab_size) 단어 집합의 크기 : 19416 단어 집합의 크기는 19,416개입니다. 이를 케라스 토크나이저의 인자로 넘겨주고 텍스트 시퀀스를 정수 시퀀스로 변환합니다. tokenizer = Tokenizer(vocab_size) tokenizer.fit_on_texts(X_train) X_train = tokenizer.texts_to_sequences(X_train) X_test = tokenizer.texts_to_sequences(X_test) 정수 인코딩이 진행되었는지 확인하고자 X_train에 대해서 상위 3개의 샘플만 출력합니다. print(X_train[:3]) [[50, 454, 16, 260, 659], [933, 457, 41, 602, 1, 214, 1449, 24, 961, 675, 19], [386, 2444, 2315, 5671, 2, 222, 9]] 각 샘플 내의 단어들은 각 단어에 대한 정수로 변환된 것을 확인할 수 있습니다. 단어의 개수는 19,416개로 제한되었으므로 0번 단어 ~ 19,415번 단어까지만 사용 중입니다. 0번 단어는 패딩을 위한 토큰임을 상기합시다. train_data에서 y_train과 y_test를 별도로 저장해줍니다. y_train = np.array(train_data['label']) y_test = np.array(test_data['label']) 5) 빈 샘플(empty samples) 제거 전체 데이터에서 빈도수가 낮은 단어가 삭제되었다는 것은 빈도수가 낮은 단어만으로 구성되었던 샘플들은 빈(empty) 샘플이 되었다는 것을 의미합니다. 빈 샘플들은 어떤 레이블이 붙어있던 의미가 없으므로 빈 샘플들을 제거해주는 작업을 하겠습니다. 각 샘플들의 길이를 확인해서 길이가 0인 샘플들의 인덱스를 받아오겠습니다. drop_train = [index for index, sentence in enumerate(X_train) if len(sentence) < 1] drop_train에는 X_train으로부터 얻은 빈 샘플들의 인덱스가 저장됩니다. 앞서 훈련 데이터(X_train, y_train)의 샘플 개수는 145,791개임을 확인했었습니다. 그렇다면 빈 샘플들을 제거한 후의 샘플 개수는 몇 개일까요? # 빈 샘플들을 제거 X_train = np.delete(X_train, drop_train, axis=0) y_train = np.delete(y_train, drop_train, axis=0) print(len(X_train)) print(len(y_train)) 145162 145162 145,162개로 샘플의 수가 줄어든 것을 확인할 수 있습니다. 6) 패딩 서로 다른 길이의 샘플들의 길이를 동일하게 맞춰주는 패딩 작업을 진행해보겠습니다. 전체 데이터에서 가장 길이가 긴 리뷰와 전체 데이터의 길이 분포를 알아보겠습니다. print('리뷰의 최대 길이 :',max(len(review) for review in X_train)) print('리뷰의 평균 길이 :',sum(map(len, X_train))/len(X_train)) plt.hist([len(review) for review in X_train], bins=50) plt.xlabel('length of samples') plt.ylabel('number of samples') plt.show() 리뷰의 최대 길이 : 69 리뷰의 평균 길이 : 10.812485361182679 가장 긴 리뷰의 길이는 69이며, 그래프를 봤을 때 전체 데이터의 길이 분포는 대체적으로 약 11내외의 길이를 가지는 것을 볼 수 있습니다. 모델이 처리할 수 있도록 X_train과 X_test의 모든 샘플의 길이를 특정 길이로 동일하게 맞춰줄 필요가 있습니다. 특정 길이 변수를 max_len으로 정합니다. 대부분의 리뷰가 내용이 잘리지 않도록 할 수 있는 최적의 max_len의 값은 몇일까요? 전체 샘플 중 길이가 max_len 이하인 샘플의 비율이 몇 %인지 확인하는 함수를 만듭니다. def below_threshold_len(max_len, nested_list): count = 0 for sentence in nested_list: if(len(sentence) <= max_len): count = count + 1 print('전체 샘플 중 길이가 %s 이하인 샘플의 비율: %s'%(max_len, (count / len(nested_list))*100)) 위의 분포 그래프를 봤을 때, max_len = 30이 적당할 것 같습니다. 이 값이 얼마나 많은 리뷰 길이를 커버하는지 확인해봅시다. max_len = 30 below_threshold_len(max_len, X_train) 전체 샘플 중 길이가 30 이하인 샘플의 비율: 94.31944999380003 전체 훈련 데이터 중 약 94%의 리뷰가 30이하의 길이를 가지는 것을 확인했습니다. 모든 샘플의 길이를 30으로 맞추겠습니다. X_train = pad_sequences(X_train, maxlen=max_len) X_test = pad_sequences(X_test, maxlen=max_len) 2. LSTM으로 네이버 영화 리뷰 감성 분류하기 하이퍼파라미터인 임베딩 벡터의 차원은 100, 은닉 상태의 크기는 128입니다. 모델은 다 대 일 구조의 LSTM을 사용합니다. 해당 모델은 마지막 시점에서 두 개의 선택지 중 하나를 예측하는 이진 분류 문제를 수행하는 모델입니다. 이진 분류 문제의 경우, 출력층에 로지스틱 회귀를 사용해야 하므로 활성화 함수로는 시그모이드 함수를 사용하고, 손실 함수로 크로스 엔트로피 함수를 사용합니다. 하이퍼파라미터인 배치 크기는 64이며, 15 에포크를 수행합니다. EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4)는 검증 데이터 손실(val_loss)이 증가하면, 과적합 징후므로 검증 데이터 손실이 4회 증가하면 정해진 에포크가 도달하지 못하였더라도 학습을 조기 종료(Early Stopping)한다는 의미입니다. ModelCheckpoint를 사용하여 검증 데이터의 정확도(val_acc)가 이전보다 좋아질 경우에만 모델을 저장합니다. validation_split=0.2을 사용하여 훈련 데이터의 20%를 검증 데이터로 분리해서 사용하고, 검증 데이터를 통해서 훈련이 적절히 되고 있는지 확인합니다. 검증 데이터는 기계가 훈련 데이터에 과적합되고 있지는 않은지 확인하기 위한 용도로 사용됩니다. from tensorflow.keras.layers import Embedding, Dense, LSTM from tensorflow.keras.models import Sequential from tensorflow.keras.models import load_model from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint embedding_dim = 100 hidden_units = 128 model = Sequential() model.add(Embedding(vocab_size, embedding_dim)) model.add(LSTM(hidden_units)) model.add(Dense(1, activation='sigmoid')) es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4) mc = ModelCheckpoint('best_model.h5', monitor='val_acc', mode='max', verbose=1, save_best_only=True) model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) history = model.fit(X_train, y_train, epochs=15, callbacks=[es, mc], batch_size=64, validation_split=0.2) 저자의 경우 조기 종료 조건에 따라서 9 에포크에서 훈련이 멈췄습니다. 훈련이 다 되었다면 테스트 데이터에 대해서 정확도를 측정할 차례입니다. 훈련 과정에서 검증 데이터의 정확도가 가장 높았을 때 저장된 모델인 'best_model.h5'를 로드합니다. loaded_model = load_model('best_model.h5') print(" 테스트 정확도: %.4f" % (loaded_model.evaluate(X_test, y_test)[1])) 테스트 정확도: 0.8544 테스트 데이터에서 85.44%의 정확도를 얻습니다. 위 코드는 뒤에서 이어질 네이버 쇼핑 리뷰 분류 실습과 한국어 스팀 리뷰 감성 분류 실습에서도 거의 동일하게 사용될 코드입니다. 3. 리뷰 예측해보기 임의의 리뷰에 대해서 예측하는 함수를 만들어보겠습니다. 기본적으로 현재 학습한 model에 새로운 입력에 대해서 예측값을 얻는 것은 model.predict()를 사용합니다. 그리고 model.fit()을 할 때와 마찬가지로 새로운 입력에 대해서도 동일한 전처리를 수행 후에 model.predict()의 입력으로 사용해야 합니다. def sentiment_predict(new_sentence): new_sentence = re.sub(r'[^ㄱ-ㅎㅏ-ㅣ가-힣 ]','', new_sentence) new_sentence = okt.morphs(new_sentence, stem=True) # 토큰화 new_sentence = [word for word in new_sentence if not word in stopwords] # 불용어 제거 encoded = tokenizer.texts_to_sequences([new_sentence]) # 정수 인코딩 pad_new = pad_sequences(encoded, maxlen = max_len) # 패딩 score = float(loaded_model.predict(pad_new)) # 예측 if(score > 0.5): print(“{:.2f}% 확률로 긍정 리뷰입니다.

“.format(score * 100)) else: print(“{:.2f}% 확률로 부정 리뷰입니다.

“.format((1 – score) * 100))

sentiment_predict(‘이 영화 개꿀잼 ㅋㅋㅋ’)

97.76% 확률로 긍정 리뷰입니다.

sentiment_predict(‘이 영화 핵노잼 ㅠㅠ’)

98.55% 확률로 부정 리뷰입니다.

sentiment_predict(‘이딴게 영화냐 ㅉㅉ’)

99.91% 확률로 부정 리뷰입니다.

sentiment_predict(‘감독 뭐하는 놈이냐?’)

98.21% 확률로 부정 리뷰입니다.

sentiment_predict(‘와 개쩐다 정말 세계관 최강자들의 영화다’)

80.77% 확률로 긍정 리뷰입니다.

ㄱ-ㅎ와 ㅏ-ㅣ 사이에 어떤 글자들이 포함되어져 있는지는 아래의 링크에서 확인할 수 있습니다.

https://www.unicode.org/charts/PDF/U3130.pdf

가-힣 사이에 어떤 글자들이 포함되어져 있는지는 아래의 링크에서 확인할 수 있습니다.

https://www.unicode.org/charts/PDF/UAC00.pdf

[python/NLP] 감정분류(한국어)- 리뷰데이터 학습, 평가, 예측까지

반응형

이번에 할 자연어처리 포스팅은 감정분류입니다 🙂

감정분류는 어떤 텍스트가 있을 때, 그 텍스트가 긍정인지, 부정인지 분류해 주는 것을 말합니다.

이번에 사용할 데이터는 감정분류 대표 예제인 네이버 영화 리뷰 데이터를 가지고

감정분류를 위한 전처리, 모델링, 학습, 예측까지 진행해 보도록 하겠습니다.

데이터 준비

https://github.com/e9t/nsmc

위의 링크에 들어가서

1. ratings.txt – 전체 리뷰데이터(20만건)

2. ratings_train.txt – 학습데이터(15만건)

3. ratings_test.txt – 평가데이터(5만건)

위의 세 파일을 다운받아 주세요.

그 후 DATA 라는 폴더를 만들어 그 안에 파일들이 위치하도록 해줍니다.

데이터 분석하기

감정분류에 사용할 데이터가 어떻게 이루어져있는지 살펴보도록 하겠습니다.

어떤 데이터고 길이는 어느정도 되는지, 많이 나온 단어 수 등등을 분석하면서 추후 모델링에 대한 좋은 아이디어가 생길 수도 있기 때문입니다.

import numpy as np import pandas as pd import os import matplotlib.pyplot as plt import seaborn as sns from wordcloud import WordCloud DATA_PATH = ‘/content/sample_data/DATA/’ #데이터경로 설정 print(‘파일 크기: ‘) for file in os.listdir(DATA_PATH): if ‘txt’ in file: print(file.ljust(30)+str(round(os.path.getsize(DATA_PATH+ file) / 100000,2))+’MB’)

파일 크기는 각각 위의 사진과 같습니다.

train은 전체 데이터의 75%, test는 25%정도 됩니다.

학습할 데이터를 확인해 보도록 하겠습니다.

#트레인 파일 불러오기 train_data = pd.read_csv(DATA_PATH + ‘ratings_train.txt’,header = 0, delimiter = ‘\t’, quoting=3) train_data.head()

train파일에서는 id, document(리뷰), label(긍정인지 부정인지) 이렇게 3가지 정보를 나타내는 컬럼이 있습니다.

print(‘학습데이터 전체 개수: {}’.format(len(train_data)))

학습데이터는 그전에 언급했듯이 15만건이 있습니다. 총 15만개의 행과 3개의 열로 이루어져 있습니다.

리뷰 길이들을 확인해 보겠습니다.

#리뷰 전체길이 확인 train_length = train_data[‘document’].astype(str).apply(len) train_length.head()

앞에 5행만 대표적으로 출력했을 때 각각 리뷰의 길이는 위와 같습니다.

#리뷰 통계 정보 print(‘리뷰 길이 최댓값: {}’.format(np.max(train_length))) print(‘리뷰 길이 최솟값: {}’.format(np.min(train_length))) print(‘리뷰 길이 평균값: {:.2f}’.format(np.mean(train_length))) print(‘리뷰 길이 표준편차: {:.2f}’.format(np.std(train_length))) print(‘리뷰 길이 중간값: {}’.format(np.median(train_length))) print(‘리뷰 길이 제1사분위: {}’.format(np.percentile(train_length,25))) print(‘리뷰 길이 제3사분위: {}’.format(np.percentile(train_length,75)))

리뷰 길이에 대해 간단한 통계 분석을 해보았을 때, 리뷰는 평균적으로 35.24의 길이를 가집니다.

이번에는 리뷰에서 어떤 단어가 가장 많이 나오는지 빈도분석을 워드클라우드(wordcloud)로 해 보겠습니다.

워드클라우드를 만들기 위한 전처리로 str타입이 아닌 데이터를 모두 제거해 줍니다.

# 문자열 아닌 데이터 모두 제거 train_review = [review for review in train_data[‘document’] if type(review) is str] train_review

한글을 시각화할 것이기 때문에 한글 폰트(.ttf파일)를 다운받아 DATA파일에 위치해 주세요.

그 후 워드클라우드 시각화를 진행해 줍니다.

# 한글 폰트 설정(.ttf파일 다운로드 후 실행) wordcloud = WordCloud(DATA_PATH+’폰트.ttf’).generate(‘ ‘.join(train_review)) plt.imshow(wordcloud, interpolation=’bilinear’) plt.axis(‘off’) plt.show()

영화, 진짜, 정말, 그냥, 너무 등등의 단어가 많이 나옴을 확인 가능합니다.

학습데이터의 긍정리뷰 및 부정리뷰가 얼만큼 되는지도 확인해 보겠습니다.

#긍정 1, 부정 0 print(‘긍정 리뷰 갯수: {}’.format(train_data[‘label’].value_counts()[1])) print(‘부정 리뷰 갯수: {}’.format(train_data[‘label’].value_counts()[0]))

각각 74827개(1: 긍정), 75173개(0: 부정)가 있습니다.

대략적인 분석을 마치도록 하겠습니다.

이번에는 데이터를 전처리하여 학습할 수 있는 데이터로 만들어 주도록 하겠습니다.

데이터 전처리

데이터 전처리는 5단계로 이루어져 있습니다.

1. 정규화로 한국어만 남기기

2. 형태소 분석기로 어간 추출하기

3. 불용어 제거하기

4. 문자를 인덱스벡터로 전환하기

5. 패딩처리하기

한국어 텍스트를 전처리할 때는 konlpy를 사용하여 형태소 분석 등을 해주겠습니다.

!pip install konlpy

konlpy가 미설치 되어 있다면 위의 코드를 실행해 주세요.

그 후 학습데이터의 리뷰데이터만 뽑아 보겠습니다.

import numpy as np import pandas as pd import re import json from konlpy.tag import Okt from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.preprocessing.text import Tokenizer DATA_PATH = ‘/content/sample_data/DATA/’ # 데이터 경로 설정 train_data = pd.read_csv(DATA_PATH+’ratings_train.txt’, header = 0, delimiter=’\t’, quoting=3) train_data[‘document’][:5]

자 그럼 본격적으로 전처리를 시작해 보겠습니다.

1. 전처리를 도와주는 함수 만들기

#전처리 함수 만들기 def preprocessing(review, okt, remove_stopwords = False, stop_words =[]): #함수인자설명 # review: 전처리할 텍스트 # okt: okt객체를 반복적으로 생성하지 않고 미리 생성 후 인자로 받음 # remove_stopword: 불용어를 제거할지 여부 선택. 기본값 False # stop_words: 불용어 사전은 사용자가 직접 입력, 기본값 빈 리스트 # 1. 한글 및 공백 제외한 문자 모두 제거 review_text = re.sub(‘[^가-힣ㄱ-ㅎㅏ-ㅣ\\s]’,”,review) #2. okt 객체를 활용하여 형태소 단어로 나눔 word_review = okt.morphs(review_text,stem=True) if remove_stopwords: #3. 불용어 제거(선택) word_review = [token for token in word_review if not token in stop_words] return word_review

2. 전체 학습데이터 및 평가데이터 리뷰 전처리하기

# 전체 텍스트 전처리 stop_words = [‘은’,’는’,’이’,’가’,’하’,’아’,’것’,’들’,’의’,’있’,’되’,’수’,’보’,’주’,’등’,’한’] okt = Okt() clean_train_review = [] for review in train_data[‘document’]: # 리뷰가 문자열인 경우만 전처리 진행 if type(review) == str: clean_train_review.append(preprocessing(review,okt,remove_stopwords=True,stop_words= stop_words)) else: clean_train_review.append([]) #str이 아닌 행은 빈칸으로 놔두기 clean_train_review[:4]

#테스트 리뷰도 동일하게 전처리 test_data = pd.read_csv(DATA_PATH + ‘ratings_test.txt’, header = 0, delimiter=’\t’, quoting=3) clean_test_review = [] for review in test_data[‘document’]: if type(review) == str: clean_test_review.append(preprocessing(review, okt, remove_stopwords=True, stop_words=stop_words)) else: clean_test_review.append([])

3. 문자로 되어있는 리뷰데이터를 인덱스 벡터로 변환

학습데이터 리뷰로 단어 사전을 생성하여 리뷰데이터를 인덱스로 바꾸어 주도록 하겠습니다.

라벨데이터(긍정, 분석 감정데이터, 정답 데이터)는 벡터화 해줍니다.

# 인덱스 벡터 변환 후 일정 길이 넘어가거나 모자라는 리뷰 패딩처리 tokenizer = Tokenizer() tokenizer.fit_on_texts(clean_train_review) train_sequences = tokenizer.texts_to_sequences(clean_train_review) test_sequences = tokenizer.texts_to_sequences(clean_test_review) word_vocab = tokenizer.word_index #단어사전형태 MAX_SEQUENCE_LENGTH = 8 #문장 최대 길이 #학습 데이터 train_inputs = pad_sequences(train_sequences,maxlen=MAX_SEQUENCE_LENGTH,padding=’post’) #학습 데이터 라벨 벡터화 train_labels = np.array(train_data[‘label’]) #평가 데이터 test_inputs = pad_sequences(test_sequences,maxlen=MAX_SEQUENCE_LENGTH,padding=’post’) #평가 데이터 라벨 벡터화 test_labels = np.array(test_data[‘label’])

4. 전처리 완료된 데이터 넘파이 파일로 저장

이후 여기서 만들어준 데이터들을 학습시 사용이 용이하도록 넘파이 파일로 만들어 저장해주도록 하겠습니다.

DEFAULT_PATH = ‘/content/sample_data/’ # 경로지정 DATA_PATH = ‘CLEAN_DATA/’ #.npy파일 저장 경로지정 TRAIN_INPUT_DATA = ‘nsmc_train_input.npy’ TRAIN_LABEL_DATA = ‘nsmc_train_label.npy’ TEST_INPUT_DATA = ‘nsmc_test_input.npy’ TEST_LABEL_DATA = ‘nsmc_test_label.npy’ DATA_CONFIGS = ‘data_configs.json’ data_configs={} data_configs[‘vocab’] = word_vocab data_configs[‘vocab_size’] = len(word_vocab) + 1 #전처리한 데이터들 파일로저장 import os if not os.path.exists(DEFAULT_PATH + DATA_PATH): os.makedirs(DEFAULT_PATH+DATA_PATH) #전처리 학습데이터 넘파이로 저장 np.save(open(DEFAULT_PATH+DATA_PATH+TRAIN_INPUT_DATA,’wb’),train_inputs) np.save(open(DEFAULT_PATH+DATA_PATH+TRAIN_LABEL_DATA,’wb’),train_labels) #전처리 테스트데이터 넘파이로 저장 np.save(open(DEFAULT_PATH+DATA_PATH+TEST_INPUT_DATA,’wb’),test_inputs) np.save(open(DEFAULT_PATH+DATA_PATH+TEST_LABEL_DATA,’wb’),test_labels) #데이터 사전 json으로 저장 json.dump(data_configs,open(DEFAULT_PATH + DATA_PATH + DATA_CONFIGS,’w’),ensure_ascii=False)

저는 CLEAN_DATA라는 폴더에 저장해 주었습니다.

학습하기

1. 학습데이터 및 전처리 데이터 불러오기

# 학습 데이터 불러오기 import tensorflow as tf from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint from tensorflow.keras import layers import numpy as np import pandas as pd import matplotlib.pyplot as plt import os import json from tqdm import tqdm #전처리 데이터 불러오기 DATA_PATH = ‘/content/sample_data/CLEAN_DATA/’ DATA_OUT = ‘/content/sample_data/DATA_OUT/’ INPUT_TRAIN_DATA = ‘nsmc_train_input.npy’ LABEL_TRAIN_DATA = ‘nsmc_train_label.npy’ DATA_CONFIGS = ‘data_configs.json’ train_input = np.load(open(DATA_PATH + INPUT_TRAIN_DATA,’rb’)) train_input = pad_sequences(train_input,maxlen=train_input.shape[1]) train_label = np.load(open(DATA_PATH + LABEL_TRAIN_DATA,’rb’)) prepro_configs = json.load(open(DATA_PATH+DATA_CONFIGS,’r’))

2. 파라미터 세팅하기

model_name= ‘cnn_classifier_kr’ BATCH_SIZE = 512 NUM_EPOCHS = 10 VALID_SPLIT = 0.1 MAX_LEN = train_input.shape[1] kargs={‘model_name’: model_name, ‘vocab_size’:prepro_configs[‘vocab_size’],’embbeding_size’:128, ‘num_filters’:100,’dropout_rate’:0.5, ‘hidden_dimension’:250,’output_dimension’:1}

3. 모델 함수 만들기

학습 모델은 CNN분류 모델로 학습을 진행하도록 하겠습니다.

class CNNClassifier(tf.keras.Model): def __init__(self, **kargs): super(CNNClassifier, self).__init__(name=kargs[‘model_name’]) self.embedding = layers.Embedding(input_dim=kargs[‘vocab_size’], output_dim=kargs[’embbeding_size’]) self.conv_list = [layers.Conv1D(filters=kargs[‘num_filters’], kernel_size=kernel_size, padding=’valid’,activation = tf.keras.activations.relu, kernel_constraint = tf.keras.constraints.MaxNorm(max_value=3)) for kernel_size in [3,4,5]] self.pooling = layers.GlobalMaxPooling1D() self.dropout = layers.Dropout(kargs[‘dropout_rate’]) self.fc1 = layers.Dense(units=kargs[‘hidden_dimension’], activation = tf.keras.activations.relu, kernel_constraint=tf.keras.constraints.MaxNorm(max_value=3.)) self.fc2 = layers.Dense(units=kargs[‘output_dimension’], activation=tf.keras.activations.sigmoid, kernel_constraint= tf.keras.constraints.MaxNorm(max_value=3.)) def call(self,x): x = self.embedding(x) x = self.dropout(x) x = tf.concat([self.pooling(conv(x)) for conv in self.conv_list], axis = 1) x = self.fc1(x) x = self.fc2(x) return x

4. 학습하기

에포크는 10으로 주어 학습을 진행하고, 검증 정확도가 그전보다 낮아지면 학습을 멈추도록 설계하였습니다.

from tensorflow.keras.models import save_model model = CNNClassifier(**kargs) model.compile(optimizer=tf.keras.optimizers.Adam(), loss = tf.keras.losses.BinaryCrossentropy(), metrics = [tf.keras.metrics.BinaryAccuracy(name=’accuracy’)]) #검증 정확도를 통한 EarlyStopping 기능 및 모델 저장 방식 지정 earlystop_callback = EarlyStopping(monitor=’val_accuracy’, min_delta=0.0001, patience=2) checkpoint_path = DATA_OUT + model_name +’\weights.h5′ checkpoint_dir = os.path.dirname(checkpoint_path) if os.path.exists(checkpoint_dir): print(“{} — Folder already exists

“.format(checkpoint_dir)) else: os.makedirs(checkpoint_dir, exist_ok=True) print(“{} — Folder create complete

“.format(checkpoint_dir)) cp_callback = ModelCheckpoint( checkpoint_path, monitor = ‘val_accuracy’, verbose=1, save_best_only = True, save_weights_only=True ) history = model.fit(train_input, train_label, batch_size=BATCH_SIZE, epochs = NUM_EPOCHS, validation_split=VALID_SPLIT, callbacks=[earlystop_callback, cp_callback]) # 모델 저장하기 save_model(model,’모델 저장할 폴더 경로’)

평가하기

위에서 학습한 모델이 저장이 되었고, 그 저장된 모델을 가지고 평가데이터를 넣어 얼마나 정답을 맞추는지 검증해 보도록 하겠습니다.

INPUT_TEST_DATA = ‘nsmc_test_input.npy’ LABEL_TEST_DATA = ‘nsmc_test_label.npy’ SAVE_FILE_NM = ‘weights.h5′ test_input = np.load(open(DATA_PATH+INPUT_TEST_DATA,’rb’)) test_input = pad_sequences(test_input,maxlen=test_input.shape[1]) test_label_data = np.load(open(DATA_PATH + LABEL_TEST_DATA, ‘rb’)) model.load_weights(‘모델저장위치/weights.h5’) model.evaluate(test_input, test_label_data)

약 82.6%의 정확도를 보입니다.

예측하기

마지막으로, 저장된 학습모델을 가지고 새로운 문장이 있을 때 그 문장이 긍정인지 부정인지 예측해 보겠습니다.

import numpy as np import pandas as pd import re import json from konlpy.tag import Okt from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.preprocessing.text import Tokenizer okt = Okt() tokenizer = Tokenizer() DATA_CONFIGS = ‘data_configs.json’ prepro_configs = json.load(open(‘/content/sample_data/CLEAN_DATA/’+DATA_CONFIGS,’r’)) prepro_configs[‘vocab’] = word_vocab tokenizer.fit_on_texts(word_vocab) MAX_LENGTH = 8 #문장최대길이 sentence = input(‘감성분석할 문장을 입력해 주세요.: ‘) sentence = re.sub(r'[^ㄱ-ㅎㅏ-ㅣ가-힣\\s ]’,”, sentence) stopwords = [‘은’,’는’,’이’,’가’,’하’,’아’,’것’,’들’,’의’,’있’,’되’,’수’,’보’,’주’,’등’,’한’] # 불용어 추가할 것이 있으면 이곳에 추가 sentence = okt.morphs(sentence, stem=True) # 토큰화 sentence = [word for word in sentence if not word in stopwords] # 불용어 제거 vector = tokenizer.texts_to_sequences(sentence) pad_new = pad_sequences(vector, maxlen = MAX_LENGTH) # 패딩 model.load_weights(‘/content/sample_data/DATA_OUT/cnn_classifier_kr\weights.h5’) #모델 불러오기 predictions = model.predict(pad_new) predictions = float(predictions.squeeze(-1)[1]) if(predictions > 0.5): print(“{:.2f}% 확률로 긍정 리뷰입니다.

“.format(predictions * 100)) else: print(“{:.2f}% 확률로 부정 리뷰입니다.

“.format((1 – predictions) * 100))

이렇게 직접 리뷰 문장을 입력하여 긍정리뷰인지 부정리뷰인지 확인이 가능합니다 🙂

전체 코드

https://colab.research.google.com/drive/1PkuR9r9WrAXHBq3TLePCiOEgYwuFx2lO?usp=sharing

학습된 모델파일

https://drive.google.com/drive/folders/13FqdLc-8BbtMptJZgtaN390Ot96J8I4y?usp=sharing

my_models.zip파일입니다.

Github

https://github.com/ElenaLim/NLP_EmotionA.git

전처리, 학습, 검증, 예측의 각 파트가 분리된 .py 파일이 있습니다.

참고자료

책 – 텐서플로2와 머신러닝으로 시작하는 자연어처리

마무리

오늘 감정분석 대표적인 영화리뷰 데이터로 감정분류를 해 보았는데

개인적으로는 예측 부분이 가장 재밌는것 같습니다 ㅎㅎ

다른 오픈데이터도 있다면 시간될 때 다른 모델, 데이터로 감정 분류를 진행해 보도록 하겠습니다 🙂

++22.06.09 : 모델 저장부분 추가 및 학습된 모델 업로드

++22.09.07: 전처리, 학습, 검증, 예측 파트로 분리된 각각의 .py파일 추가(깃허브 링크)

반응형

[Python] 소셜 데이터의 감성 예측

미리 크롤링한 영화 댓글 자료

from sklearn . linear_model import LogisticRegression from sklearn . model_selection import GridSearchCV clf = LogisticRegression ( random_state = 0 ) params = { ‘C’ : [ 15 , 18 , 19 , 20 , 22 ] } grid_cv = GridSearchCV ( clf , param_grid = params , cv = 3 , scoring = ‘accuracy’ , verbose = 1 ) grid_cv . fit ( tfv_train_x , train_y ) print ( grid_cv . best_params_ , grid_cv . best_score_ )

[파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2

비지도학습 기반 감성 분석¶

비지도 감성 분석은 Lexicon을 기반으로 한다. Lexicon은 NLTK 패키지의 서브 모듈로 감성을 분석하기 위해 지원하는 감성 어휘 사전을 의미하고, 감성 사전은 긍정 감성 또는 부정 감성의 정도를 의미하는 수치를 가지고 있는데 이를 감성 지수라고 한다. 이 감성 지수는 단어의 위치나 주변 단어, 문맥, POS(Part of Speech) 등을 참고해 결정된다.

텍스트 분석에는 문맥상 의미를 나타내는 semantic이라는 용어가 자주 등장하는데 동일한 단어나 문장이라도 다른 환경과 문맥에서 다르게 표현되거나 이해될 수 있기 때문이다. 언어학에서 이러한 semantic을 표현하기 위해서 여러 가지 규칙을 정해왔으며 NLP 패키지는 semantic을 프로그램적으로 인터페이스할 수 있는 다양한 방법을 제공한다. 특히 NLP 패키지의 WordNet 모듈을 통해 semantic 분석을 진행할 수 있고 이 모듈은 다양한 상황에서 같은 어휘라도 다르게 사용되는 어휘의 semantic 정보를 제공하며 이를 위해 각각의 품사로 구성된 개별 단어를 Synset(Sets of cognitive synonyms)이라는 개념을 이용해 표현한다. Synset은 단순한 하나의 단어가 아니라 그 단어가 가지는 문맥, semantic 정보를 제공하는 WordNet의 핵심 개념이다. 하지만 NLTK 감성 사전은 예측 성능이 그리 좋지 않다는 단점이 있다.

[Python] 뉴스 감성지수 분류 모델

728×90

반응형

https://sieon-dev.tistory.com/4

위 사이트를 개발할 때 사용한 감성지수 분류 모델에 대해 기록을 남겨볼까 합니다.

Preview

사실 처음에는 뉴스 데이터를 활용하여 다음날의 주가를 예측하는 모델을 만들고 싶었지만 다양한 방법들을 시도하여도 예측 정확도가 60%대 밖에 나오지 않아 차라리 감성지수를 예측하는 모델을 설계하는 방향으로 바꿨습니다.

감성지수는 영화 리뷰와 같이 리뷰와 평점이 있는 데이터를 학습시켜 새로운 리뷰가 달렸을 때 해당 리뷰의 감성(감정) 값을 예측하는 모형에 많이 사용됩니다. 이 방법론을 적용하여 뉴스와 뉴스가 나온 다음 날의 주가를 학습시켜 다음날 주가를 예측하는 모델을 만들어보자 했던 것이 처음 시도였고 이게 정확도가 높지가 않아 그럼 뉴스와 뉴스의 감성 분류 값을 학습시키는 모델로 바뀌었던 것이죠.

영화 리뷰같은 경우는 사용자가 리뷰를 남김과 동시에 별점을 남기기 때문에 종속변수를 손쉽게 라벨링(긍정이면 1, 부정이면 0)할 수 있지만 뉴스는 그렇지 않아 이 뉴스를 긍정으로 봐야 할지 부정으로 봐야 할지 정하는 것이 정말 애매합니다. 그래서 저는 제가 개발한 방법대로 감성사전을 만들었습니다. 예를 들어 어제 “FOMC 금리 인상 가능성 있어”와 같은 제목의 뉴스가 나왔고 오늘 코스피 종가가 어제보다 올랐으면 “FOMC”, “금리”, “인상”, “가능성” (“있어”는 명사가 아니므로)에 긍정 점수를 부여하고 반대로 떨어졌으면 부정 점수를 부여하는 방식으로 말이죠. 이렇게 만든 감성사전의 모든 단어들의 평균점수보다 새로운 뉴스의 단어들의 평균점수가 높으면 1, 아니면 0으로 라벨링을 한 후 학습을 진행했습니다. 다행히도 이 모델의 감성 분류 예측 정확도를 보니 91%까지 올랐습니다.

1. 데이터 수집

뉴스 데이터는 빅카인즈 에서 경제 섹터의 뉴스를 2017년 1월 1일부터 2021년 3월 30일까지 총 500,194 건을 수집하였습니다.

2. 데이터 전처리

뉴스의 제목만을 사용하기 때문에 날짜와 제목을 제외한 컬럼은 제거 후 야후 파이낸스에서 Kospi 데이터를 다운로드하여 뉴스데이터에 붙였습니다. 뉴스와 뉴스가 나온 다음날 코스피 종가가 전날 대비 상승했으면 1, 아니면 0으로 말이죠. 추가로 불용어를 제거하고 Okt 라이브러리를 사용해서 명사만을 추출한 칼럼을 추가했습니다.

okt = Okt() n_ = [] title_rename = [] for i in range(len(df)): if(i % 10000 ==0): print(i,”단계 완료”) title_rename.append(re.sub(“[\(\[].*?[\)\]]”, “”,df.iloc[i][‘제목’])) n_.append(‘ ‘.join(okt.nouns(df.iloc[i][‘제목’]))) df[‘nouns’] = n_ df[‘제목’]=title_rename df = df[df[‘nouns’]!=”] #2차 불용어 제거 df[‘제목’] = df[‘제목’].str.replace(“[^ㄱ-ㅎㅏ-ㅣ가-힣 ]”,””) df[‘제목’].replace(”, np.nan, inplace=True) df = df.dropna(how=’any’)

라벨의 비율 1: 269861 0: 228765

Train : Test의 비율 400000 : 98626 로 분할 후 빈 행 제거

3. 감성사전 구축

한 글자인 단어는 제거하고 두 글자 이상인 단어들의 점수를 초기화해주었습니다.

총 47229개의 단어가 등장했습니다.

up = 269861 down = 228765 up_ratio = up/(up+down) down_ratio = down/(up+down) import collections for i,w in enumerate(df[‘nouns’]): w = w.split(‘ ‘) if (df.iloc[i][‘updown’]==1): for j in range(len(w)): noun = w[j] if len(noun)<=1: continue vocab[noun] = vocab[noun] + down_ratio else: for j in range(len(w)): noun = w[j] if len(noun)<=1: continue vocab[noun] = vocab[noun] - up_ratio 이 처럼 상승비율과 하락비율을 정의해준 다음 라벨 값이 1이면 하락 비율을 각 단어에 더해주고 라벨값이 0이면 상승 비율을 차감해주었습니다. 라벨값이 1이면 상승인데 왜 상승 비율을 더해주지 않았냐면 만약 라벨값이 1인 데이터가 아닌 데이터보다 훨씬 많다면 해당 단어들의 점수가 너무 커져서 점수가 고르지 못한 감성사전이 만들어지기 때문에 정규화를 해준 셈이죠. 결과는 이렇습니다. 감성사전 이제 만들어진 감성사전을 활용하여 뉴스의 평균 감성 점수를 산출한 뒤 칼럼에 추가했습니다. total = [] for i,w in enumerate(df_train['nouns']): sent_score = 0 w= w.split(' ') for j in w: if(len(j)<=1): continue elif(j not in sent_dictionary): continue else: sent_score = sent_score + sent_dictionary[j] total.append(sent_score/len(w)) df_train['sent_score'] = total Train Set *감성사전을 만들 땐 전체 데이터를 사용하여 만들었기 때문에 어떻게 보면 Train set에 Test set의 정보까지도 들어가 있는 문제가 있습니다. 처음 모델을 만들 땐 Train set만을 사용해서 감성사전을 만들었지만 Test set에 있는 단어들이 들어가지 않는다는 문제점(예를 들어 코로나)이 있어 최종 웹에 Deploy 하기 위한 모델은 전체 데이터를 사용해서 감성사전을 구축했습니다. 이후 sent_score가 감성사전의 평균 점수보다 높으면 1, 낮으면 0으로 새롭게 라벨링을 해주었습니다. sum = 0 for i in range(len(vocab)): sum = sum + list(vocab.values())[i] sent_mean = sum/len(vocab) a_ = [] for i in range(len(df_train)): if(df_train.iloc[i]['sent_score']>sent_mean): a_.append(1) else: a_.append(0) df_train[‘sent_label’] = a_

위 과정을 Test set에도 적용하여 데이터 전처리를 완료하였습니다.

4. 모델링

모델링하기에 앞서 Colab에서 형태소 분류기인 Mecab 설치를 해줘야 합니다. 앞서 감성사전을 구축할 땐 Okt 라이브러리를 사용했지만 Mecab이 성능이 훨씬 빠르기 때문에 Mecab으로 넘어왔습니다.

#Mecab 설치 !git clone https://github.com/SOMJANG/Mecab-ko-for-Google-Colab.git %cd Mecab-ko-for-Google-Colab !bash install_mecab-ko_on_colab190912.sh !pip install Mecab

모델링에는 Bi-LSTM 모델을 사용하였습니다. Bert도 사용해봤지만 성능면에서는 Bi-LSTM이 미세한 차이로 좋게 나왔습니다.

우선 validation set과 train set을 나눠준 뒤 형태소를 분류하고 X와 Y 값을 지정해줍니다.

train_data, validation_data = train_test_split(df_train, test_size = 0.2, random_state = 42) train_data.dropna(how=’any’,inplace= True) validation_data.dropna(how=’any’, inplace=True) mecab = Mecab() train_data[‘tokenized’] = train_data[‘제목’].apply(mecab.morphs) validation_data[‘tokenized’] = validation_data[‘제목’].apply(mecab.morphs) X_train = train_data[‘tokenized’].values Y_train = train_data[‘sent_label’].values X_vali= validation_data[‘tokenized’].values Y_vali = validation_data[‘sent_label’].values

이후 keras의 Tokenizer를 사용해 텍스트를 시퀀스 벡터로 변환합니다. (모델의 Input으로는 텍스트가 들어갈 수 없기 때문)

#vocab_size는 단어 집합의 크기 tokenizer = Tokenizer(vocab_size, oov_token = ‘OOV’) tokenizer.fit_on_texts(X_train) X_train = tokenizer.texts_to_sequences(X_train) X_vali = tokenizer.texts_to_sequences(X_vali)

X_train의 형태

일정한 Input 형태를 만들기 위해 적절한 길이를 지정하고 padding 과정으로 마무리합니다.

def below_threshold_len(max_len, nested_list): cnt = 0 for s in nested_list: if(len(s) <= max_len): cnt = cnt + 1 print('전체 샘플 중 길이가 %s 이하인 샘플의 비율: %s'%(max_len, (cnt / len(nested_list))*100)) max_len = 30 below_threshold_len(max_len, X_train) X_train = pad_sequences(X_train, maxlen = max_len) X_vali = pad_sequences(X_vali, maxlen = max_len) 이제 모델을 구현하겠습니다. model = Sequential() model.add(Embedding(vocab_size, 100)) model.add(Bidirectional(LSTM(100))) model.add(Dense(1, activation='sigmoid')) es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4) mc = ModelCheckpoint('best_model.h5', monitor='val_acc', mode='max', verbose=1, save_best_only=True) model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) history = model.fit(X_train, Y_train, epochs=15, callbacks=[es, mc], batch_size=256, validation_split=0.2) 모델 실행결과 Validation Set의 예측 정확도는 0.92가 나왔습니다. 이제 Test Set 도 같은 과정을 거쳐 전처리를 한 후 성능을 확인해보겠습니다. Test Set의 정확도 역시 0.91로 높은 성능을 보이고 있습니다. 이후 이 모델을 웹 서버에 Deploy 하여 네이버 News API를 통해 수집한 뉴스들을 분석하는 데 사용하고 있습니다. 많은 분께 도움이 되는 포스트였으면 좋겠습니다. 추후 이 모델을 파이썬 Django에서 어떻게 사용하는지도 포스팅하겠습니다. 반응형

[파이썬] 네이버 클로바 Sentiment 문장 텍스트 감정 분석

반응형

바빠서 시간이 부족하거나 파이썬 코딩이 처음인 사람들이 많다. 누구나 손쉽게 코딩을 배우고 바로 업무자동화,디지털마케팅 등에 쓰일만한 여러 가지 파이썬 코드를 만들고 있다. 이에 파이썬 구글 블로거 API 자동 포스팅하기 를 통해 파이썬 코드 공유드린다. 이에 오늘 하루도 여러분들의 컴퓨터 업무에 자유로운 나날이 길어지길 바란다. 오늘은 네이버 클라우드 서비스 내에 보이는 API를 가져왔다. 이름하여 네이버 Sentiment API 라고 하는데, 이는 텍스트에 담긴 감정(긍정/부정/중립)을 분석해 주는 API라고 한다.

파이썬 네이버 sentiment 긍정 부정 판별 분석

https://www.ncloud.com/product/aiService/clovaSentiment

거기에 들어가서 네이버 Sentiment API 이용 신청하고, client id 와 client secret 키만 받으면 완료된다. 그럼 긍정 부정 단어를 얼마나 잘 판별해 주는지 테스트해볼까? 아래는 테스트할 컨텐츠 텍스트들을 여러가지를 집어넣어봤다.

네이버 클로바 Sentiment 문장 텍스트 감정 분석

하기 코딩은 json으로 위에 보여진 메모장 내 텍스트를 얼마나 긍정, 부정으로 판별해 줄까가 궁금해서 넣어보았다. 800단어씩 시범으로 돌려보기로 한다.(1000~1500자까지 된다고는 하는데, 이상하게 에러가 발생되는경우가 있어서 800단어로 세팅했다.)

import json file = open(‘C:/Users/user/raw/naver_blog/positive_negative_text_result.txt’, ‘w’, encoding=’utf8′) #결과파일 n = 1 #첫번째 m = 800 #두번째 for i in range(1, 2) : #41번 client_id = “” #클라이언트 키 client_secret = “” #클라이언트 시크릿 키 url=”https://naveropenapi.apigw.ntruss.com/sentiment-analysis/v1/analyze” headers = { “X-NCP-APIGW-API-KEY-ID”: client_id, “X-NCP-APIGW-API-KEY”: client_secret, “Content-Type”: “application/json” } f = open(‘C:/Users/user/raw/naver_blog/blog_content.txt’, ‘r’, encoding=’utf8′) text = f.read() text_2 = text.replace(”

“, “”) text_3 = text_2.replace(“________________”, ” “) content = text_3[n:m] #800단어씩 data = { “content”: content } print(json.dumps(data, indent=4, sort_keys=True)) response = requests.post(url, data=json.dumps(data), headers=headers) rescode = response.status_code if(rescode == 200): print (response.text) else: print(“Error : ” + response.text) f.close() text = response.json() raw = text[‘sentences’] max_cnt = len(raw) #리스트 개수 for i in range(0, max_cnt) : content = str(raw[i][‘content’]) #텍스트 offset = int(raw[i][‘highlights’][0][‘offset’]) #오프셋 length = int(raw[i][‘highlights’][0][‘length’]) #해당 길이 text = content[offset : offset + length] #부정 의미가 있는 문구 텍스트 추출 #print(text) file.write(str(text) + ‘

‘) n += 800 m += 800 file.close()

먼저 아래와 같이 나오긴 했는데, 보아하니 문장 1줄을 읽고, 이에 빠른 offset, 해당 문장 길이(length), 그리고 sentiment 판별결과 (긍정, 부정, 중립 이렇게 있는것 같다.) 이외 confidence 라고 해서 각 negative, positive, neutral 등의 지수를 적어주는 것 같다. highlights 는 해당 분석된 문장을 보여주는것 같다. 그럼 긍정 텍스트가 담긴 텍스트만 뽑아볼까?

네이버 클로바 Sentiment 문장 텍스트 감정 분석

아래는 해당 텍스트된 문장에서 긍정 의미를 가진 걸로 판명된 문장만 따로 텍스트 추출하는 걸로 해봤다.

max_cnt = len(raw) #리스트 개수 for i in range(0, max_cnt) : if (raw[i][‘sentiment’] == ‘positive’) : #긍정 의미를 가질경우 content = str(raw[i][‘content’]) #텍스트 offset = int(raw[i][‘highlights’][0][‘offset’]) #오프셋 length = int(raw[i][‘highlights’][0][‘length’]) #해당 길이 text = content[offset : offset + length] #긍정 의미가 있는 문구 텍스트 추출 print(text)

밑에가 그 결과다. 보아하니 긍정적인 부문만 잘 긁어서 가져다 보는것 같다. (역시 네이버 AI 기술도 좋다..)

보아하니 이런식으로 긍정, 부정 의미가 담긴 리뷰를 저렇게 판별 분석을 해서 뭔가 이용한다면은 굉장히 긍정적인 용도로 쓸 수 있을 것 같다. 차후엔 텍스트 추출 이후 해당 텍스트 내 감정 분석 등을 통해 좋은 부문을 광고 문구 등에 응용할 수 있는 방안도 찾아보면 좋을 것 같다.

네이버 클로바 Sentiment 문장 텍스트 감정 분석

반응형

키워드에 대한 정보 감성 분석 파이썬

다음은 Bing에서 감성 분석 파이썬 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 감정 분석 Sentiment Analysis

  • 이수안
  • 컴퓨터
  • 연구소
  • SuanLab
  • 자연어 처리
  • Natural Language Processing
  • 감정 분석
  • Sentiment Analysis
  • 감정 사전
  • afinn
  • 뉴스그룹 데이터
  • 네이버 영화 리뷰
  • 네이버 쇼핑 데이터

감정 #분석 #Sentiment #Analysis


YouTube에서 감성 분석 파이썬 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 감정 분석 Sentiment Analysis | 감성 분석 파이썬, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  십자 형광등 교체 | Led십자등(전등) 교체하기 55W (스마토Led등기구 십자등) Led Lamp Change 상위 200개 답변

Leave a Reply

Your email address will not be published. Required fields are marked *