Read More
[파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2
Article author: rahites.tistory.com
Reviews from users: 49759 Ratings
Top rated: 3.5
Lowest rated: 1
Summary of article content: Articles about [파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2 감성 분석(Sentiment Analysis)은 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법으로 소셜 미디어, 여론조사, 온라인 리뷰, … …
Most searched keywords: Whether you are looking for [파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2 감성 분석(Sentiment Analysis)은 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법으로 소셜 미디어, 여론조사, 온라인 리뷰, … # 22.02.12 머신러닝 스터디 8장. 텍스트 분석 – 2 텍스트 분석 – 2 <파이썬 머신러닝 완벽 가이드>¶ 텍스트 분석 – 2 ( p497 ~ p527 )¶ 05. 감성 분석¶ 감성 분석(Sentiment Analysis)은 문..
Table of Contents:
05 감성 분석¶
06 토픽 모델링(Topic Modeling) – 20 뉴스그룹¶
07 문서 군집화 소개와 실습(Opinoin Review 데이터 세트)¶
티스토리툴바
태그
관련글
댓글0
공지사항
최근글
인기글
최근댓글
태그
전체 방문자
[파이썬 머신러닝 완벽 가이드] 8장. 텍스트 분석 – 2
Read More
Google Colab
Article author: colab.research.google.com
Reviews from users: 24802 Ratings
Top rated: 5.0
Lowest rated: 1
Summary of article content: Articles about Google Colab 파이썬으로 감정 분석하는 방법은 크게 두 가지로 구분. 감정 어휘 사전을 이용한 감정 상태 분류. 미리 분류해둔 감정어 사전을 통해 분석하고자 하는 텍스트의 단어 … …
Most searched keywords: Whether you are looking for Google Colab 파이썬으로 감정 분석하는 방법은 크게 두 가지로 구분. 감정 어휘 사전을 이용한 감정 상태 분류. 미리 분류해둔 감정어 사전을 통해 분석하고자 하는 텍스트의 단어 …
Table of Contents:
Google Colab
Read More
[Python] 뉴스 감성지수 분류 모델
Article author: sieon-dev.tistory.com
Reviews from users: 19608 Ratings
Top rated: 4.9
Lowest rated: 1
Summary of article content: Articles about [Python] 뉴스 감성지수 분류 모델 Test Set의 정확도 역시 0.91로 높은 성능을 보이고 있습니다. 이후 이 모델을 웹 서버에 Deploy 하여 네이버 News API를 통해 수집한 뉴스들을 분석하는 … …
Most searched keywords: Whether you are looking for [Python] 뉴스 감성지수 분류 모델 Test Set의 정확도 역시 0.91로 높은 성능을 보이고 있습니다. 이후 이 모델을 웹 서버에 Deploy 하여 네이버 News API를 통해 수집한 뉴스들을 분석하는 … https://sieon-dev.tistory.com/4 [Python] 포트폴리오 최적화 서비스 제공과 텍스트마이닝을 사용한 금융 데이터 분석 해외의 포트폴리오 최적화 및 백테스트 사이트인 PortfolioVisualizer의 국내화 버전으로 개..
Table of Contents:
고정 헤더 영역
메뉴 레이어
검색 레이어
상세 컨텐츠
태그
추가 정보
페이징
티스토리툴바
[Python] 뉴스 감성지수 분류 모델
Read More
한국어 감성분석, 감성 기반 추천 시스템 제작
Article author: sig413.tistory.com
Reviews from users: 37009 Ratings
Top rated: 3.1
Lowest rated: 1
Summary of article content: Articles about 한국어 감성분석, 감성 기반 추천 시스템 제작 3달 여간의 교육을 받으며 파이썬부터 시작해서 ML, DL의 기초 OpenCV를 간단하게 다뤄보았다. 배운 것들을 토대로 모델을 만드는 프로젝트를 진행 … …
Most searched keywords: Whether you are looking for 한국어 감성분석, 감성 기반 추천 시스템 제작 3달 여간의 교육을 받으며 파이썬부터 시작해서 ML, DL의 기초 OpenCV를 간단하게 다뤄보았다. 배운 것들을 토대로 모델을 만드는 프로젝트를 진행 … 3달 여간의 교육을 받으며 파이썬부터 시작해서 ML, DL의 기초 OpenCV를 간단하게 다뤄보았다. 배운 것들을 토대로 모델을 만드는 프로젝트를 진행했다. (Jupyter notebook사용) 최대한 특이한걸 해보고 싶었지만..Github : https://github.com/DrunkJin
Table of Contents:
한국어 감성분석 감성 기반 추천 시스템 제작
티스토리툴바
한국어 감성분석, 감성 기반 추천 시스템 제작
Read More
감성 분석 — 데이터 사이언스 스쿨
Article author: datascienceschool.net
Reviews from users: 41404 Ratings
Top rated: 4.7
Lowest rated: 1
Summary of article content: Articles about 감성 분석 — 데이터 사이언스 스쿨 감성 분석¶. 앞에서 공부한 나이브 베이즈 분류 모형을 이용하여 문서에 대한 감성 분석(sentiment analysis)를 해보자. 감성 분석이란 문서에 대해 좋다(positive) … …
Most searched keywords: Whether you are looking for 감성 분석 — 데이터 사이언스 스쿨 감성 분석¶. 앞에서 공부한 나이브 베이즈 분류 모형을 이용하여 문서에 대한 감성 분석(sentiment analysis)를 해보자. 감성 분석이란 문서에 대해 좋다(positive) …
Table of Contents:
감성 분석 — 데이터 사이언스 스쿨
Read More
[Python keras] 감성 분석 딥러닝 모델 생성 – TextVectorization
Article author: tech-diary.tistory.com
Reviews from users: 5416 Ratings
Top rated: 4.0
Lowest rated: 1
Summary of article content: Articles about [Python keras] 감성 분석 딥러닝 모델 생성 – TextVectorization Python tensorflow keras. textvectorization. sentimental analysis using deep learning. 준비해야할 것 : 수집한 댓글 데이터. …
Most searched keywords: Whether you are looking for [Python keras] 감성 분석 딥러닝 모델 생성 – TextVectorization Python tensorflow keras. textvectorization. sentimental analysis using deep learning. 준비해야할 것 : 수집한 댓글 데이터. Python tensorflow keras textvectorization sentimental analysis using deep learning 준비해야할 것 : 수집한 댓글 데이터 훈련 데이터(Train Data)를 생성하기 위해 약 900개의 댓글을 하나하나 레이블링(Labe..
Table of Contents:
태그
‘Python techNLP’ Related Articles
[Python keras] 감성 분석 딥러닝 모델 생성 – TextVectorization
Read More
See more articles in the same category here: Top 109 tips update new.
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파일입니다.
참고자료
책 – 텐서플로2와 머신러닝으로 시작하는 자연어처리
마무리
오늘 감정분석 대표적인 영화리뷰 데이터로 감정분류를 해 보았는데
개인적으로는 예측 부분이 가장 재밌는것 같습니다 ㅎㅎ
다른 오픈데이터도 있다면 시간될 때 다른 모델, 데이터로 감정 분류를 진행해 보도록 하겠습니다 🙂
++22.06.09 : 모델 저장부분 추가 및 학습된 모델 업로드
반응형
【실습】 Python >> Text Mining — 감성 분류 분석 (호텔 리뷰 데이터)
제주 호텔의 리뷰 데이터(평가 점수 + 평가 내용)을 활용해 다음 2가지 분석을 진행합니다:
>> 사용할 Library
>> 사용할 데이터셋
Tripadvisor 여행사이트에서 “제주 호텔”로 검색해서 나온 리뷰들을 활용합니다. (평점 & 평가 내용 포함)
>> Feature Description
“text” 내용을 확인해보면, 소량의 “특수 문자”와 “모음”이 존재하는 경우가 있습니다. 이들은 Text Mining을 적용할 의미가 없기 때문에 정규표현식을 이용해서 제거해보도록 할게요.
기계가 텍스트 형식으로 되어 있는 리뷰 데이터를 이해하려면, 텍스트 데이터를 단어 단위로 분리하는 전처리 괴정이 필요합니다. 여기서 분리된 단어들은 Bag of Words로 Count 기반으로 나타날 수도 있고, TF-IDF를 통해서 점수로 나타날 수도 있습니다.
먼저 리뷰의 평가 내용을 단어화해서 형태소를 추출하고, 그 다음 Bag of Words를 생성하여 TF-IDF 변환을 진행하겠습니다.
영문이 아닌 한글을 처리해야 하기 때문에 “konlpy”이라는 library를 사용합니다.
Requirement already satisfied: konlpy==0.5.2 in d:\anaconda\lib\site-packages (0.5.2) Requirement already satisfied: jpype1 in d:\anaconda\lib\site-packages (1.0.2) Requirement already satisfied: Jpype1-py3 in d:\anaconda\lib\site-packages (0.5.5.4) Requirement already satisfied: tweepy>=3.7.0 in d:\anaconda\lib\site-packages (from konlpy==0.5.2) (3.9.0) Requirement already satisfied: lxml>=4.1.0 in d:\anaconda\lib\site-packages (from konlpy==0.5.2) (4.5.0) Requirement already satisfied: colorama in d:\anaconda\lib\site-packages (from konlpy==0.5.2) (0.4.3) Requirement already satisfied: numpy>=1.6 in d:\anaconda\lib\site-packages (from konlpy==0.5.2) (1.18.1) Requirement already satisfied: beautifulsoup4==4.6.0 in d:\anaconda\lib\site-packages (from konlpy==0.5.2) (4.6.0) Requirement already satisfied: typing-extensions; python_version < "3.8" in d:\anaconda\lib\site-packages (from jpype1) (3.7.4.1) Requirement already satisfied: requests[socks]>=2.11.1 in d:\anaconda\lib\site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (2.23.0) Requirement already satisfied: requests-oauthlib>=0.7.0 in d:\anaconda\lib\site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (1.3.0) Requirement already satisfied: six>=1.10.0 in d:\anaconda\lib\site-packages (from tweepy>=3.7.0->konlpy==0.5.2) (1.14.0) Requirement already satisfied: chardet<4,>=3.0.2 in d:\anaconda\lib\site-packages (from requests[socks]>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (3.0.4) Requirement already satisfied: certifi>=2017.4.17 in d:\anaconda\lib\site-packages (from requests[socks]>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (2020.6.20) Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in d:\anaconda\lib\site-packages (from requests[socks]>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (1.25.8) Requirement already satisfied: idna<3,>=2.5 in d:\anaconda\lib\site-packages (from requests[socks]>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (2.9) Requirement already satisfied: PySocks!=1.5.7,>=1.5.6; extra == “socks” in d:\anaconda\lib\site-packages (from requests[socks]>=2.11.1->tweepy>=3.7.0->konlpy==0.5.2) (1.7.1) Requirement already satisfied: oauthlib>=3.0.0 in d:\anaconda\lib\site-packages (from requests-oauthlib>=0.7.0->tweepy>=3.7.0->konlpy==0.5.2) (3.1.0)
So you have finished reading the 파이썬 감성 분석 topic article, if you find this article useful, please share it. Thank you very much. See more: 한국어 감성분석 파이썬, 파이썬 감성분석 코드, 파이썬 텍스트 감성분석, 파이썬 lexicon 감성분석, 뉴스 감성분석 파이썬, 한국어 텍스트 감성분석, 파이썬 감성사전, lstm 감성분석