[숙제]
- 리뷰 데이터를 이용해 긍정/부정 워드 클라우드 만들기
- 리뷰로 긍정/부정 분류하는 모델 만들기
import pandas as pd
import numpy as np
#판다스를 사용하여 네이버 쇼핑 리뷰 데이터가 존재하는 URL을 입력하고 다운로드합니다.
df = pd.read_table('https://raw.githubusercontent.com/bab2min/corpus/master/sentiment/naver_shopping.txt', names=['ratings', 'reviews'])
df
import matplotlib as mpl
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'
!apt -qq -y install fonts-nanum
import matplotlib.font_manager as fm
fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumBarunGothic')
mpl.font_manager._rebuild()
# null 값 확인
print(df.isnull().sum())
#Result
ratings 0
reviews 0
dtype: int64
# 중복 값 확인
print(df.nunique())
df.drop_duplicates(subset=['reviews'], inplace=True)
#Result
ratings 4
reviews 199908
dtype: int64
# 별점이 몇개나 있나 확인
df['ratings'].value_counts()
#Reulst
5 81170
2 63948
1 36007
4 18783
Name: ratings, dtype: int64
# 워드클라우드를 위해 형태소 분석기 다운로드
!pip install konlpy
from konlpy.tag import Okt
tokenizer = Okt()
# 엄청 오래걸림
df['tokenized'] = df['reviews'].apply(tokenizer.nouns)
# 불용어는 두고, 1글자는 뺌
df['tokenized'] = df['tokenized'].apply(lambda x: [item for item in x if len(item)>1])
# 긍정, 부정을 3점을 기준으로 나눠주기
df_positive = df[df['ratings']>3]
df_negative = df[df['ratings']<3]
# 긍정, 부정에 해당되는 단어들을 하나의 리스트로 묶어주기
positive_words = np.hstack(df_positive['tokenized'].values)
negative_words = np.hstack(df_negative['tokenized'].values)
print(positive_words, negative_words)
#Result
['배공' '아주' '바지' ... '제품' '본적' '배송'] ['택배' '엉망' '선물' ... '다음' '장마' '런가']
# 워드 클라우드 다운로드
from wordcloud import WordCloud
# 긍정 부정 단어 리스트를 각각 temp_data에 넣고 워드 클라우드 생성
plt.figure(figsize = (15,15))
temp_data = ' '.join(negative_words)
wc = WordCloud(max_words = 2000 , width = 1600 , height = 800, font_path = fontpath).generate(temp_data)
plt.imshow(wc, interpolation = 'bilinear')
# 긍정리뷰 (평점 3이상)에는 1, 부정리뷰(평점 3이하)에는 0 라벨링
df['label'] = np.select([df.ratings>3], [1], default=0)
# 훈련 데이터 / 테스트 데이터 나누기
# x_train : reviews 70% / x_test : reviews 30% / y_train : label 70% / y_test : label 30%
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(df['reviews'], df['label'], test_size = 0.3)
# 사이킷런 다운로드
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
vector = CountVectorizer() # DTM 벡터화를 위한 객체 생성
x_train_dtm = vector.fit_transform(x_train) # x_train 벡터화
x_test_dtm = vector.transform(x_test) # x_test 벡터화
tfidf_transformer = TfidfTransformer() # tfidf 벡터화를 위한 객체 생성
tfidfv = tfidf_transformer.fit_transform(x_train_dtm) # x_train_dtm에 대해서 벡터화 진행
tfidfv_test = tfidf_transformer.transform(x_test_dtm) # x_test_dtm에 대해서 벡터화 진행
print(tfidfv)
from sklearn.linear_model import LogisticRegression # 로지스틱 회귀 함수 임포트
from sklearn.metrics import accuracy_score # 정확도 계산
# 사이킷런의 로지스틱 회귀 모델 학습
lr = LogisticRegression (C=10000, penalty='l2')
lr.fit(tfidfv, y_train)
# 정확도 예측
predicted = lr.predict(tfidfv_test)
print ("정확도 :", accuracy_score(y_test, predicted))
#Result
정확도 : 0.8565020926083404
x_test_dtm = vector.transform(['사용', '배송']) # x_test 벡터화
tfidfv_test = tfidf_transformer.transform(x_test_dtm) # x_test_dtm에 대해서 벡터화 진행
predicted = lr.predict(tfidfv_test)
print (predicted)
#Result
[0 0]
데이터 정리할 때 같은 입력값
으로 다른 타깃(결과)
가 나오면 안 되어서 중복된 데이터는 다 제외하였다. 그런데 리뷰와 평점이 동일한 값을 가진 데이터만 뽑아보는 방법이 궁금하여 확인해보았다.
방법1)
df_duplicated[df.duplicated() == True]
방법2)
df.loc[df.duplicated(), :]
모델 실행 시 transform()
에 문자열은 안 됨.