정보 / / 2024. 10. 31. 00:32

[자연어처리] 한국어 텍스트 감정구분 모델 예제 - RandomForest

반응형

  • 네이버 영화 리뷰 데이터를 전처리하고, TF-IDF 토큰나이져를 활용하여 토큰화하고 머신러닝으로 모델링 만들고 감성분류 수행합니다.

 

 

 

참고 사이트

 


 

 



 

A. 머신러닝 이용하여 자연어 Classification하기

  • 네이버 영화 리뷰 데이터를 가지고
  • RandomForest/SGD 모델 학습하여 감정 Classification 모델링해 보겠습니다.
 
 

1. 라이브러리 임포트

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import urllib.request
plt.rc('font', family='NanumBarunGothic')
 

2. 파일 읽어오기

# 네이버 영화 리뷰 데이터 읽어오기
# 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")

!git clone https://github.com/e9t/nsmc.git
 
Cloning into 'nsmc'...
remote: Enumerating objects: 14763, done.
remote: Counting objects: 100% (14762/14762), done.
remote: Compressing objects: 100% (13012/13012), done.
remote: Total 14763 (delta 1748), reused 14762 (delta 1748), pack-reused 1 (from 1)
Receiving objects: 100% (14763/14763), 56.19 MiB | 21.75 MiB/s, done.
Resolving deltas: 100% (1748/1748), done.
Updating files: 100% (14737/14737), done.
 
# 데이터 확인하기
final_data = pd.read_csv("./nsmc/ratings.txt", delimiter='\t', quoting=3)
 
final_data.head(3)
 
iddocumentlabel012
8112052 어릴때보고 지금다시봐도 재밌어요ㅋㅋ 1
8132799 디자인을 배우는 학생으로, 외국디자이너와 그들이 일군 전통을 통해 발전해가는 문화산... 1
4655635 폴리스스토리 시리즈는 1부터 뉴까지 버릴께 하나도 없음.. 최고. 1
 
# 총 200000 건
final_data.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200000 entries, 0 to 199999
Data columns (total 3 columns):
 #   Column    Non-Null Count   Dtype 
---  ------    --------------   ----- 
 0   id        200000 non-null  int64 
 1   document  199992 non-null  object
 2   label     200000 non-null  int64 
dtypes: int64(2), object(1)
memory usage: 4.6+ MB
 

 

3. 전처리 : Null, 중복 제거

# final_data 어떤 컬럼과 내용으로 되어 있는지 다시 확인
final_data.tail()
 
# '문장' 컬럼의 내용을 양끝의 빈공간 삭제
final_data['document'] = final_data['document'].str.strip()
 
# Null 있는지 확인 : 없음
final_data.isnull().sum()
 
0iddocumentlabel
0
8
0

dtype: int64
 
# null 데이터 삭제
final_data.dropna(inplace=True)
 
# 중복 데이터 있는지 확인 : 중복 존재 확인
final_data['document'].duplicated().sum()
 
5449
 
# 중복 데이터 제거
final_data.drop_duplicates(subset=['document'], inplace=True)
 
# info 정보 확인
final_data.info()
 
<class 'pandas.core.frame.DataFrame'>
Index: 194543 entries, 0 to 199999
Data columns (total 3 columns):
 #   Column    Non-Null Count   Dtype 
---  ------    --------------   ----- 
 0   id        194543 non-null  int64 
 1   document  194543 non-null  object
 2   label     194543 non-null  int64 
dtypes: int64(2), object(1)
memory usage: 5.9+ MB
 

 

4. 영문, 숫자, 특수문자 제거

# '문장' 컬럼의 내용중에 영문, 특수문자 있는지 확인 : 영문과 특수문자 존재 확인
final_data[ final_data['document'].str.contains('[^가-힣 ]') ].head(3)
 
iddocumentlabel012
8112052 어릴때보고 지금다시봐도 재밌어요ㅋㅋ 1
8132799 디자인을 배우는 학생으로, 외국디자이너와 그들이 일군 전통을 통해 발전해가는 문화산... 1
4655635 폴리스스토리 시리즈는 1부터 뉴까지 버릴께 하나도 없음.. 최고. 1
 
# '문장' 컬럼의 내용에서 숫자, 영문자, 특수문자등의 글자는 삭제처리
# final_data['문장'].replace('[^가-힣 ]','', regex=True) : 이렇게도 가능

final_data['document'] = final_data['document'].str.replace('[^가-힣 ]','', regex=True)
 
# '문장' 컬럼의 내용에서 영문, 특수문자 없음 확인
final_data['document'][final_data['document'].str.contains('[^가-힣 ]')].sum()
 
0
 
# 숫자, 영문자, 특수문자 등 제거후 데이터 확인하기.
final_data.head(3)
 
iddocumentlabel012
8112052 어릴때보고 지금다시봐도 재밌어요 1
8132799 디자인을 배우는 학생으로 외국디자이너와 그들이 일군 전통을 통해 발전해가는 문화산업... 1
4655635 폴리스스토리 시리즈는 부터 뉴까지 버릴께 하나도 없음 최고 1
 

5. Label 분포 확인

# label '감정' 분포 확인 : 총 6개이며, 고루게 분포 확인. 단 기쁨이 약간 부족해 보임
final_data['label'].value_counts()
 
countlabel01
97277
97266

dtype: int64
 

6. X, Y 분리

# X, Y 분리

features = final_data['document']
labels = final_data['label']
 
features.shape, labels.shape
 
((194543,), (194543,))
 
# features 내용 3개 출력
features.head(3), labels.head(3)
 
(0                                    어릴때보고 지금다시봐도 재밌어요
 1    디자인을 배우는 학생으로 외국디자이너와 그들이 일군 전통을 통해 발전해가는 문화산업...
 2                     폴리스스토리 시리즈는 부터 뉴까지 버릴께 하나도 없음 최고
 Name: document, dtype: object,
 0    1
 1    1
 2    1
 Name: label, dtype: int64)
 
print('이벤트 문자열 최대 길이 :{}'.format(max(len(l) for l in features)))
print('이벤트 문자열 평균 길이 :{}'.format(sum(map(len, features))/len(features)))
 
이벤트 문자열 최대 길이 :140
이벤트 문자열 평균 길이 :32.56406038767779
 
# 히스토그램을 보면 30~40 부근에 많이 몰려 있음 알수 있다.
plt.hist([len(s) for s in features], bins=50)
plt.xlabel('length of samples')
plt.ylabel('number of samples')
plt.show()
 

7. train set와 test set 분리

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(features, labels , test_size=0.2, random_state=41)
x_train.shape, x_test.shape, y_train.shape, y_test.shape
 
((155634,), (38909,), (155634,), (38909,))
 

7. TF-IDF 변환하기

# 말뭉치를 TF-IDF로 변환하기

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer()
x_train_v = tfidf.fit_transform( x_train )
x_test_v = tfidf.transform( x_test )

y_train_v = y_train.copy()
y_test_v = y_test.copy()
 
# 각 라인의 각 단어에 대한 TF-IDF 값 표현
print(x_train_v[:3])
 
# 학습데이터셋의 TF-IDF 매트릭스 확인하기 : 41259 라인, 47366 단어
x_train_v.shape
 
(155634, 306861)
 
print(x_test_v[:1])
 

8. 머신러닝 모델링

# 전체 데이터로 학습하는 1분 내외 소요 : 성능 76% 나옴, 성능 잘 나옴.

from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import SGDClassifier
import time

start = time.time()

# rfc = RandomForestClassifier()
# rfc.fit(x_train_v, y_train_v)
# print(f'RandomForestClassifier 성능 : { rfc.score(x_test_v, y_test_v) }')

sgdc = SGDClassifier()
sgdc.fit(x_train_v, y_train_v)
print(f'SGDClassifier 성능 : { sgdc.score(x_test_v, y_test_v) }')

end = time.time()
print(f'총학습시간: { end - start }')
 
SGDClassifier 성능 : 0.76529851705261
총학습시간: 0.2772693634033203
 

10. 예측해 보기

# 출력 결과 해석 : (0, 44327)	0.241660101642553
# 0 : 첫라인, 44327 : 단어에 맵핑된 번호, 0.241660101642553 : tf-idf 계산 값

print(f'검증데이터셋의 첫번째 TF-IDF : {x_test_v[:1]}')
 
검증데이터셋의 첫번째 TF-IDF :   (0, 37669)	0.32179648415569073
  (0, 64486)	0.46224340396439156
  (0, 79316)	0.3773767865467077
  (0, 113329)	0.4469586451306701
  (0, 122155)	0.3577255327170683
  (0, 155269)	0.2472916313660645
  (0, 188060)	0.18777104866665684
  (0, 296883)	0.3409019131309016
 
print(f'검증데이터셋의 첫번째 TF-IDF 역변환 : {tfidf.inverse_transform(x_test_v[:1])}')
 
검증데이터셋의 첫번째 TF-IDF 역변환 : [array(['나에겐', '돌이키고', '마지막에는', '보기전으로', '불쌍', '싶다', '영화를', '허나'],
      dtype='<U139')]
 
# RandomForest 모델로 예측하기
predict = sgdc.predict(x_test_v[:1])
print(predict)
 
[1]
 




 
 
 
 
 
 

 

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유