데이터분석 2주차 숙제 - 📄 네이버 쇼핑 리뷰 데이터
📄 네이버 쇼핑 리뷰 데이터를 이용해 각각 긍정/부정 리뷰의 워드 클라우드를 만들어보고, 긍정/부정을 분류할 수 있는 모델을 만들어보세요.
- 새로운 리뷰를 보고 긍정적인지, 부정적인지를 분류할 수 있는 모델을 만들면 완성!('너무 배송이 느리고 별로에요' 라는 리뷰를 부정리뷰라고 잘 분류한 것을 볼 수 있습니다.
- (아래 예시는 부정 리뷰는 0, 긍정 리뷰는 1 이라는 번호를 부여하고 예측을 진행한 것입니다.
- 아래 순서대로 시작해보세요!
-
- Colab에서 한글 사용을 위한 세팅하기
- [코드스니펫] - 한글 사용을 위한 세팅
- 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()
- # 해당 코드 실행 후 반드시 상단의 런타임 > 런타임 다시 시작을 눌러주세요.
- 아래의 코드는 Colab에서 한글을 사용하기 위해 세팅하는 용도일뿐, 코드를 이해하지 않으셔도 상관없습니다.
-
- 데이터 로드하기
- [코드스니펫] - 2주차 숙제 데이터 로드 코드
- # 과제를 하는데 이 두 개의 패키지만 필요하다는 것이 아닙니다! # 여러분들이 과제를 하면서 필요한 패키지들을 파악하고 계속 추가하여 임포트해주세요. 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
-
- 긍정, 부정 분류 모델 구축을 위한 가이드라인 (필독!)
- 데이터를 불러온다 (read_table)
- df = pd.read_table('<https://raw.githubusercontent.com/bab2min/corpus/master/sentiment/naver_shopping.txt>', names=['ratings', 'reviews'])
- 'A를 이용해서 B를 예측' 하려고 할 때, A는 벡터화를 진행하고, B는 단순한 번호로 치환하는 인덱스화를 진행한다. (우선 인덱스화를 먼저!)2-1. 긍정/부정인지 여부(B)에 대한 인덱스화 2-2. 훈련 데이터 / 테스트 데이터 나누기그럴 경우 그냥 각각 불러와서 사용하면 됐었지만, 지금 숙제에서는 데이터가 하나의 데이터프레임에 담겨있기 때문에, 이를 직접 훈련 데이터 / 테스트 데이터로 나눠줘야 합니다.아래처럼 왼쪽에는 x_train, x_test, y_train, y_test 라고 적어주시고, (꼭 4개 다 적어야합니다!)그러면 왼쪽에 명시한 변수들인
- x_train (훈련에 사용할 리뷰 데이터)
- x_test (테스트에 사용할 리뷰 데이터)
- y_train (훈련에 사용할 긍정/부정 여부)
- y_test (테스트에 사용할 긍정/부정 여부)
# dtm 을 만들고, dtmvector = CountVectorizer() x_train_dtm = dtmvector.fit_transform(x_train) # dtm 을 이용해서 tfidf 벡터를 생성 tfidf_transformer = TfidfTransformer() tfidfv = tfidf_transformer.fit_transform(x_train_dtm)
# 평점이 3보다 크면 긍정 리뷰, 3과 같거나 3보다 작으면 부정 리뷰이므로 # 평점이 3보다 크면 1로 지정, 3과 같거나 3보다 작으면 0으로 지정 df['label'] = np.select([df.ratings > 3], [1], default=0)
- 아래는 훈련용 데이터인 x_train 을 벡터화하는 과정입니다!
- 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)
- (데이터들이 담길 때는 test_size 에 명시한 비율대로 훈련 / 테스트 데이터가 나눠서 담겨지게 됩니다. 0.3 이라고 명시하면, 지금 있는 전체 데이터 중에 70% 는 훈련 데이터에 담기고, 30% 는 테스트 데이터에 담기게 됩니다.)
- 오른쪽에는 train_test_split(예측에 사용할 데이터: 여기서는 리뷰 (A), 예측할 데이터: 여기서는 긍정/부정 여부 (B), test_size = 원하는 테스트 데이터 셋의 크기) 이렇게 3가지를 명시해주면 됩니다.
- 그럴 때 사용할 수 있는 것이 train_test_split이라는 함수입니다.
- 강의에서는 훈련 데이터 / 테스트 데이터가 이미 나누어져 있는 데이터를 사용했었습니다.
- 현재 데이터는 평점 - 리뷰 이렇게 이루어져있는데, 평점이 3보다 크면 긍정 리뷰로, 3과 같거나 3보다 작으면 부정 리뷰로 분류하면 됩니다.
- 지금은 리뷰(A)를 이용해서 긍정/부정(B)을 예측하려고 하고 있기 때문에, 리뷰에 대해서는 DTM, TFIDF로 만드는 벡터화를 진행하고, 긍정/부정인지 여부는 단순히 1/0 으로 치환하면 됩니다.
- 모델을 생성하고 학습시키기
- # 로지스틱 회귀를 활용한 모델 학습 예시 lr = LogisticRegression(C=10000, penalty='l2') lr.fit(tfidfv, y_train)
- 테스트 데이터를 활용해서 정확도 확인하기
- x_test_dtm = dtmvector.transform(x_test) #테스트 데이터를 DTM으로 변환 tfidfv_test = tfidf_transformer.transform(x_test_dtm) #DTM을 TF-IDF 행렬로 변환 predicted = lr.predict(tfidfv_test) #테스트 데이터에 대한 예측 print("정확도:", accuracy_score(y_test, predicted)) #예측값과 실제값 비교
- 전체적인 과정은 아래와 같습니다.
-
-
- 최종적으로 워드 클라우드 이미지와 소스 코드를 제출해주시면 됩니다! 🙂HW. 2주차 숙제 해설
- [코드스니펫] - 2주차 숙제 정답 코드https://colab.research.google.com/drive/1nLJc_QJiRl7DWB8ALQojxTIgzh06s-dW?usp=sharing
- import pandas as pd import numpy as np import matplotlib.pyplot as plt df = pd.read_table('<https://raw.githubusercontent.com/bab2min/corpus/master/sentiment/naver_shopping.txt>', names=['ratings', 'reviews']) print(df['reviews'].nunique()) # 중복 샘플 제거 df.drop_duplicates(subset=['reviews'], inplace=True) df['ratings'].value_counts().plot(kind = 'bar') print(df.groupby('ratings').size().reset_index(name = 'count')) ########################### !pip install konlpy from konlpy.tag import Okt tokenizer = Okt() df['tokenized'] = df['reviews'].apply(tokenizer.nouns) # 리뷰 점수가 4~5점이면 1, 리뷰 점수가 1~2면 0의 값을 줍니다. df['label'] = np.select([df.ratings > 3], [1], default=0) df.head() positive_reviews = np.hstack(df[df['label']==1]['tokenized'].values) negative_reviews = np.hstack(df[df['label']==0]['tokenized'].values) ############################
여기는 답안해설과 코랩 실 코드들
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()
# 해당 코드 실행 후 반드시 상단의 런타임 > 런타임 다시 시작을 눌러주세요.
# 과제를 하는데 이 두 개의 패키지만 필요하다는 것이 아닙니다!
# 여러분들이 과제를 하면서 필요한 패키지들을 파악하고 계속 추가하여 임포트해주세요.
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 pandas as pd # 판다스
import numpy as np # 넘파이
import matplotlib.pyplot as plt # 맷플롯립
print(df['reviews'].nunique())
# 중복 샘플 제거
df.drop_duplicates(subset=['reviews'], inplace=True)
df
df['ratings'].value_counts().plot(kind = 'bar')
!pip install konlpy
from konlpy.tag import Okt
tokenizer = Okt()
df['tokenized'] = df['reviews'].apply(tokenizer.nouns)
# 리뷰 점수가 4~5점이면 1, 리뷰 점수가 1~2면 0의 값을 줍니다.
df['label'] = np.select([df.ratings > 3], [1], default=0)
df.head()
positive_reviews = np.hstack(df[df['label']==1]['tokenized'].values)
negative_reviews = np.hstack(df[df['label']==0]['tokenized'].values)
from collections import Counter
positive_reviews_word_count = Counter(positive_reviews)
print(positive_reviews_word_count.most_common(20))
negative_reviews_word_count = Counter(negative_reviews)
print(negative_reviews_word_count.most_common(20))
import numpy as np
from wordcloud import WordCloud
# 긍정 리뷰의 워드 클라우드
plt.figure(figsize = (15,15))
temp_data = ' '.join(positive_reviews)
wc = WordCloud(max_words = 2000 , width = 1600 , height = 800, font_path = fontpath).generate(temp_data)
plt.imshow(wc, interpolation = 'bilinear')
plt.figure(figsize = (15,15))
temp_data = ' '.join(negative_reviews)
wc = WordCloud(max_words = 2000 , width = 1600 , height = 800, font_path = fontpath).generate(temp_data)
plt.imshow(wc, interpolation = 'bilinear')
from sklearn.naive_bayes import MultinomialNB # 다항분포 나이브 베이즈 모델
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score #정확도 계산
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.model_selection import train_test_split
앞서 워드클라우드를 만들기 위해서 부정, 긍정 리뷰를 나눴었는데 이번에는 굳이 나눌 필요 없이, 평점에 따라 부정 리뷰는 0, 긍정 리뷰는 1 로 나눈 상태에서 진행하면됩니다.:
df = pd.read_table('https://raw.githubusercontent.com/bab2min/corpus/master/sentiment/naver_shopping.txt', names=['ratings', 'reviews'])
df['label'] = np.select([df.ratings > 3], [1], default=0)
x_train, x_test, y_train, y_test = train_test_split(df['reviews'], df['label'], test_size = 0.3)
dtmvector = CountVectorizer()
x_train_dtm = dtmvector.fit_transform(x_train)
tfidf_transformer = TfidfTransformer()
tfidfv = tfidf_transformer.fit_transform(x_train_dtm)
나이브베이즈 분류기, 로지스틱 회귀, SVM 중 어떤 것을 쓰셔도 상관없습니다.
---
여기서는 로지스틱 회귀를 이용해서 진행하겠습니다!
lr = LogisticRegression(C=10000, penalty='l2')
lr.fit(tfidfv, y_train)
x_test_dtm = dtmvector.transform(x_test) #테스트 데이터를 DTM으로 변환
tfidfv_test = tfidf_transformer.transform(x_test_dtm) #DTM을 TF-IDF 행렬로 변환
predicted = lr.predict(tfidfv_test) #테스트 데이터에 대한 예측
print("정확도:", accuracy_score(y_test, predicted)) #예측값과 실제값 비교
아래는 그냥 번외로, 임의로 작성한 리뷰에 대해서 모델이 어떻게 예측하는지를 한번 테스트해보았습니다. '너무 배송이 느리고 별로에요' 라는 리뷰에 대해서 '0', 즉 부정적 리뷰라고 분류한 것을 확인할 수 있습니다!
x_test_dtm = dtmvector.transform(['너무 배송이 느리고 별로에요']) #테스트 데이터를 DTM으로 변환
tfidfv_test = tfidf_transformer.transform(x_test_dtm) #DTM을 TF-IDF 행렬로 변환
predicted = lr.predict(tfidfv_test) #테스트 데이터에 대한 예측
print(predicted)