Sun.El Data Analysis

[자연어처리] 네이버 영화 평점 정보 분석(konlpy - Twitter, sklearn - TfidfVectorizer, LogisticRegression, GridSearchCV, accuracy_score)_ 본문

Machine Learning

[자연어처리] 네이버 영화 평점 정보 분석(konlpy - Twitter, sklearn - TfidfVectorizer, LogisticRegression, GridSearchCV, accuracy_score)_

Sun.El 2023. 7. 31. 23:28
728x90
총 200,000개 리뷰로 구성된 영화 리뷰에 대한 긍정(1), 부정(0) 평가한 데이터를 이용하여
자연어처리와 리뷰 긍정/부정 평가 머신모델을 만들자
데이터 다운로드 링크 : https://github.com/e9t/nsmc/

 

1. 데이터 이해 및 전처리

add check point!
1. re.sub('패턴', '바꿀문자열', '문자열', 바꿀횟수)
2. lambda
[In]
import pandas as pd
#https://github.com/e9t/nsmc
train_df = pd.read_csv('./0731/ratings_train.txt', sep='\t')
test_df = pd.read_csv('./0731/ratings_test.txt', sep='\t')
train_df.head(3)​

[Out]

[In]
#학습데이터의 레이블
print(train_df['label'].value_counts())
print(train_df.info())​

[Out]

#부정(0): 75173개, 긍정(1): 74827개
0    75173
1    74827

Name: label, dtype: int64
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150000 entries, 0 to 149999
Data columns (total 3 columns):
 #   Column    Non-Null Count   Dtype 
---  ------    --------------   ----- 
 0   id        150000 non-null  int64 
 1   document  149995 non-null  object
 2   label     150000 non-null  int64 
dtypes: int64(2), object(1)
memory usage: 3.4+ MB
None

[In]

import re

train_df = train_df.fillna(' ')
# \d+ - 1개 이상 숫자가 나오면 공백으로 변경
train_df['document'] = train_df['document'].apply(lambda x : re.sub(r"\d+", " ", x))

test_df = test_df.fillna(' ')
test_df['document'] = test_df['document'].apply(lambda x :re.sub(r"\d+", " ", x))

#칼럼 삭제
train_df.drop('id', axis=1, inplace =True)
test_df.drop('id', axis=1, inplace=True)

 

2. 형태소 분석(TfidfVectorizer)

Tfiidfvectorizer

매개변수

[In]
from sklearn.feature_extraction.text import TfidfVectorizer

#TfidfVectorizer() 매개변수
#ngram_range = (1,2) : go back, go home / ngram_range = (1,1) : go, back, home
#min_df=3 : 최소빈도값을 설정, df = 문서의 수
#max_df = 0.9, 90%이상 나타나는 단어는 무시하겠다(10개 문장에서 9번 이상 나오는 단어는 무시)
#Term Frequency(TF), Document Frequency(IDF score), TF-IDF score
tfidf_vect = TfidfVectorizer(tokenizer=tw_tokenizer, ngram_range=(1,2), min_df=3, max_df= 0.9)

#TfidfVectorizer.fit(text)를 통해 text가 가지고 있는 모든 단어를 BoW로 구성하고, 
#이 단어들에 대해 Tf-idf 값을 계산한 뒤 각 단어의 인덱스 위치에 Tf-idf 값이 들어간 벡터가 만들어짐
tfidf_vect.fit(train_df['document'])

#fit_transform 메서드를 이용하면 문서 단어 행렬을 만들어줌
tfidf_vect_matrix_train = tfidf_vect.transform(train_df['document'])

print(tfidf_vect_matrix_train.shape)​

[Out]

#학습 데이터 Text의 vectorizer shape
(150000, 129276)

 

3. 머신러닝(sklearn - LogisticRegression) 구축 및 평가

LogisticRegression

GridSearchCV

accuracy_score

[In]
# Logistic Regression 이용 감성 분석 Classification 수행
lg_clf = LogisticRegression(random_state = 0)
# Parameter C 최적화 - GridSearchCV
params = {'C': [1, 3.5, 4.5, 5.5, 10]}
grid_cv = GridSearchCV(lg_clf, param_grid=params, cv= 3, scoring='accuracy', verbose = 1)
grid_cv.fit(tfidf_vect_matrix_train, train_df['label'])
print(grid_cv.best_params_, round(grid_cv.best_score_, 4))​

[Out]

Fitting 3 folds for each of 5 candidates, totalling 15 fits
{'C': 3.5} 0.8593

[In]

from sklearn.metrics import accuracy_score
# 학습 데이터를 적용한 TfidfVectorizer를 이용
# 테스트 데이터를 TF-IDF 값으로 Feature 변환
tfidf_matrix_test = tfidf_vect.transform(test_df['document'])
# 최적 파라미터로 학습된 classifier를 그대로 이용
best_estimator = grid_cv.best_estimator_
preds = best_estimator.predict(tfidf_matrix_test)
print('Logistic Regression 정확도: ', accuracy_score(test_df['label'], preds) )

[Out]

Logistic Regression 정확도:  0.86188

[In]

result = pd.DataFrame({
         "document" : test_df['document'],
         "test" : test_df['label'],
         "pred" : preds
         })
result

[out]

 

4. 새로운 데이터로 모델 성능 확인

[In]
text = '최고의 액션 영화입니다'
if best_estimator.predict(tfidf_vect.transform([text])) == 0:
    print(f'"{text}" -> 부정일 가능성이{round(best_estimator.predict_proba(tfidf_vect.transform([text]))[0][0],2)*100}% 입니다.')
else:
    print(f'"{text}" -> 긍정일 가능성이{round(best_estimator.predict_proba(tfidf_vect.transform([text]))[0][1],2)*100}% 입니다.')​

[Out]

"최고의 액션 영화입니다" -> 긍정일 가능성이99.0% 입니다.

[In]

text = '영화 재미없네요'
if best_estimator.predict(tfidf_vect.transform([text])) == 0:
    print(f'"{text}" -> 부정일 가능성이{round(best_estimator.predict_proba(tfidf_vect.transform([text]))[0][0],2) *100}% 입니다.')
else:
    print(f'"{text}" -> 긍정일 가능성이{round(best_estimator.predict_proba(tfidf_vect.transform([text]))[0][1],2) *100}% 입니다.')

[Out]

"영화 재미없네요" -> 부정일 가능성이99.0% 입니다.