강의/데이터분석

데이터분석 2주차 숙제 - 📄 네이버 쇼핑 리뷰 데이터

MotherCarGasoline 2022. 1. 26. 16:55

📄 네이버 쇼핑 리뷰 데이터를 이용해 각각 긍정/부정 리뷰의 워드 클라우드를 만들어보고, 긍정/부정을 분류할 수 있는 모델을 만들어보세요.

 

  • 새로운 리뷰를 보고 긍정적인지, 부정적인지를 분류할 수 있는 모델을 만들면 완성!('너무 배송이 느리고 별로에요' 라는 리뷰를 부정리뷰라고 잘 분류한 것을 볼 수 있습니다. 
  • (아래 예시는 부정 리뷰는 0, 긍정 리뷰는 1 이라는 번호를 부여하고 예측을 진행한 것입니다.
  • 아래 순서대로 시작해보세요!
      1. Colab에서 한글 사용을 위한 세팅하기
      앞서 강의에서 진행했던 것과 마찬가지로 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 상단의 런타임 - 런타임 다시 시작 을 클릭하여 런타임을 재시작합니다.이제 Colab에서 실습을 하던 중 워드클라우드에서 한글이 깨지지 않도록 하기 위한 세팅을 마쳤습니다!
    • 아래의 코드는 Colab에서 한글을 사용하기 위해 세팅하는 용도일뿐, 코드를 이해하지 않으셔도 상관없습니다.

       
        1. 데이터 로드하기
        • [코드스니펫] - 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
        1. 긍정, 부정 분류 모델 구축을 위한 가이드라인 (필독!)
        처음 내용을 접하시는 분들에게는 모델 구축 과정이 어렵기 때문에, 한번 더 전체적인 과정을 설명드리고자 합니다.
        1. 데이터를 불러온다 (read_table)
        2. df = pd.read_table('<https://raw.githubusercontent.com/bab2min/corpus/master/sentiment/naver_shopping.txt>', names=['ratings', 'reviews'])
        3. '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 (테스트에 사용할 긍정/부정 여부)
          각각에 자동으로 데이터들이 담기게 됩니다!아래는 숙제 데이터를 훈련 데이터 / 테스트 데이터로 나누는 예시 코드입니다.2-3. 리뷰(A)에 대한 벡터화
          # dtm 을 만들고,
          dtmvector = CountVectorizer()
          x_train_dtm = dtmvector.fit_transform(x_train)
          
          # dtm 을 이용해서 tfidf 벡터를 생성
          tfidf_transformer = TfidfTransformer()
          tfidfv = tfidf_transformer.fit_transform(x_train_dtm)
          
        4. # 평점이 3보다 크면 긍정 리뷰, 3과 같거나 3보다 작으면 부정 리뷰이므로 # 평점이 3보다 크면 1로 지정, 3과 같거나 3보다 작으면 0으로 지정 df['label'] = np.select([df.ratings > 3], [1], default=0)
        5. 아래는 훈련용 데이터인 x_train 을 벡터화하는 과정입니다!
        6. 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)
        7. (데이터들이 담길 때는 test_size 에 명시한 비율대로 훈련 / 테스트 데이터가 나눠서 담겨지게 됩니다. 0.3 이라고 명시하면, 지금 있는 전체 데이터 중에 70% 는 훈련 데이터에 담기고, 30% 는 테스트 데이터에 담기게 됩니다.)
        8. 오른쪽에는 train_test_split(예측에 사용할 데이터: 여기서는 리뷰 (A), 예측할 데이터: 여기서는 긍정/부정 여부 (B), test_size = 원하는 테스트 데이터 셋의 크기) 이렇게 3가지를 명시해주면 됩니다.
        9. 그럴 때 사용할 수 있는 것이 train_test_split이라는 함수입니다.
        10. 강의에서는 훈련 데이터 / 테스트 데이터가 이미 나누어져 있는 데이터를 사용했었습니다.
        11. 현재 데이터는 평점 - 리뷰 이렇게 이루어져있는데, 평점이 3보다 크면 긍정 리뷰로, 3과 같거나 3보다 작으면 부정 리뷰로 분류하면 됩니다.
        12. 지금은 리뷰(A)를 이용해서 긍정/부정(B)을 예측하려고 하고 있기 때문에, 리뷰에 대해서는 DTM, TFIDF로 만드는 벡터화를 진행하고, 긍정/부정인지 여부는 단순히 1/0 으로 치환하면 됩니다.
        13. 모델을 생성하고 학습시키기
        14. # 로지스틱 회귀를 활용한 모델 학습 예시 lr = LogisticRegression(C=10000, penalty='l2') lr.fit(tfidfv, y_train)
        15. 테스트 데이터를 활용해서 정확도 확인하기
        16. 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)