[BigData] 웹 크롤링을 통해서 영화 리뷰를 통한 영화 장르 결정
Description
- 여기서 추천 장르의 기준은 40%로 하여, 고객이 많이 본 장르이면서 동시에 영화사에서는 조금이라도 많은 장르에 대한 영화 추천 알림을 보내 고객은 더 즐겁고, 영화 극장가에서는 편리한 방향으로 프로그램을 구축하였다.
-
고객 맞춤별 추천 상품은 고객의 니즈를 맞춰 정확하게 파악하는 것이 중요하다. 그러면서 동시에 영화 극장가에 수익이 있어야 하므로, 다음과 같은 아이디어를 제공하고자 한다.
영화 추천을 위한 기준점을 40%이상의 영화 관람일 경우로 정한다.
5가지 장르내에서 한 가지의 장르가 50%이상인 경우 추천을 하게 되면, 결국 특정 한 가지의 장르에 대한 영화만 추천을 해주어야 한다. 물론 고객의 입장에서는 보다 정확한 추천 알고리즘을 통해서 만족도를 향상시킬 수 있지만, 반대로 영화 극장가에서는 한 가지의 장르의 영화만 추천을 해야 되는 알고리즘이라면 불리하게 적용될 수 있다. 그렇기 때문에 40%를 기준으로 잡아서 조금 더 융통성 있는 방향으로 추천 알고리즘 구축에 도움이 될 수 있다.
영화 예매 날짜를 통해서 관람 날짜가 3개월 이상 차이가 나는 경우, 그 다음 추천 알림을 공지할 떼, 할인 쿠폰을 제공한다.
관심 장르의 영화 개봉 이전에 사전 우선 예매권을 제공하여 영화 극장가에 유익한 정보를 제공할 수 있도록 한다.
위에서 리뷰가 없는 개봉 이전의 영화 같은 경우는 사전 예매를 한 관객들의 리뷰와 평화 평론가의 리뷰가 중요한데, 관심 장르와 관련된 영화 리뷰같은 경우는 더욱 자세할 가능성이 높기 때문에 이를 활용하여, 영화 극장가에서는 질 좋은 정보를 얻고, 관객은 먼저 영화를 개봉할 기회를 얻게 되어 쌍방으로 이익을 취할 수 있는 알고리즘 구축에 도움이 될 수 있다. 이때의 특정 장르 시청 기준이 60% 이상으로 잡아서 더욱 유익한 정보 제공에 도움이 될수 있도록 사전 우선 예매권에 대한 기준치를 올린다.
Environment
Python
Contributions
손수경, 윤소영, 최민영
Progress
1️⃣ 데이터 전처리
리뷰 내에서 필요 없는 말들을 다 지운다.
import requests as req
from bs4 import BeautifulSoup as bs
url = 'https://www.imdb.com/title/tt6932874/reviews?ref_=tt_urv' #보스 베이비
res = req.get(url)
soup = bs(res.text, 'html.parser')
review_list = soup.find_all('div', {"class":"content"})
review_list = [review.text.strip() for review in review_list]
print (review_list)
rev = ''.join(review_list)
N = rev.replace("Was this review helpful? Sign in to vote.", "")
A = N.replace("\n", "")
K = A.replace("Permalink", "")
import re
E = re.sub('\d{0,2} out of \d{0,2} found this helpful', "", K)
D = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…》]', '', E)
li = D.lower()
F = re.sub("movie", "", li)
G = re.sub("film", "", F)
H = re.sub("character","", G)
I = re.sub("helpful","", H)
J = re.sub("review","", I)
K = re.sub("reviews","", J)
L = re.sub("sign","", K)
N = re.sub("vote", "", L)
2️⃣ 단어 빈도수에 따른 딕셔너리 만들기
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(N)
result = []
for w in word_tokens:
if w not in stop_words:
result.append(w)
from collections import Counter
import os, csv
import stat
cnt = Counter(result) #result에 있는 모든 단어의 개수를 세서 큰수대로 딕셔너리에 추가
print (cnt)
>>>
Counter({'good': 19, 'kids': 18, 'first': 17, 'baby': 17, 'one': 17, 'like': 14,
'boss': 14, 'much': 11, 'funny': 11, 'didnt': 10, 'family': 9, 'even': 8, 'pretty': 8,
'really': 8, 'new': 8, 'nice': 7, 'tim': 7, 'bad': 7, 'isnt': 6, 'liked': 6, 'message': 6,
'story': 6, 'fun': 5, 'lot': 5, 'sequel': 5, 'actually': 5, 'animation': 5, 'tina': 5,
'voice': 5, 'every': 5, 'better': 5, 'thought': 5, 'time': 5, 'dont': 4, 'quite': 4,
'say': 4, 'fine': 4, 'alec': 4, 'interesting': 4, 'business': 4, 'awful': 4, 'way': 4,
'know': 4, 'great': 4, 'love': 4, 'could': 4, 'netflix': 4,
,,,
3️⃣ 장르별 단어 출현 빈도수
from collections import Counter
import os, csv
import stat
cnt = Counter(result) #result에 있는 모든 단어의 개수를 세서 큰수대로 딕셔너리에 추가
print (cnt)
ani = 0
ani += cnt['animated']
ani += cnt['disney']
ani += cnt['kid']
ani += cnt['animation']
comedy = 0
comedy += cnt['fun']
comedy += cnt['funny']
comedy += cnt['comic']
comedy += cnt['hummor']
comedy += cnt['joke']
comedy += cnt['laugh']
comedy += cnt['comedy']
action = 0
action += cnt['action']
action += cnt['acting']
horror = 0
horror += cnt['horror']
horror += cnt['dark universe']
horror += cnt['mystery']
horror += cnt['missing']
horror += cnt['murder']
horror += cnt['weird']
horror += cnt['scary']
horror += cnt['horrible']
drama = 0
drama += cnt['drama']
drama += cnt['people']
drama += cnt['development']
drama += cnt['life']
drama += cnt['foster']
drama += cnt['journey']
drama += cnt['friend']
drama += cnt['society']
4️⃣ 파이플롯으로 차트 그리기
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from math import pi
from matplotlib.path import Path
from matplotlib.spines import Spine
from matplotlib.transforms import Affine2D
## 데이터 준비
sum_val = ani+comedy+action+horror+drama
df = pd.DataFrame({'Movie' : ['boss baby'], 'Animated' : [ani/sum_val*15], 'Comedy' : [comedy/sum_val*15], 'Action' : [action/sum_val*15], 'Horror' : [horror/sum_val*15], 'Drama' : [drama/sum_val*15]})
## 하나로 합치기 - 폴리곤
labels = df.columns[1:]
num_labels = len(labels)
angles = [x/float(num_labels)*(2*pi) for x in range(num_labels)] ## 각 등분점
angles += angles[:1] ## 시작점으로 다시 돌아와야하므로 시작점 추가
my_palette = plt.cm.get_cmap("Set2", len(df.index))
fig = plt.figure(figsize=(8,8))
fig.set_facecolor('white')
ax = fig.add_subplot(polar=True)
for i, row in df.iterrows():
color = my_palette(i)
data = df.iloc[i].drop('Movie').tolist()
data += data[:1]
ax.set_theta_offset(pi / 2) ## 시작점
ax.set_theta_direction(-1) ## 그려지는 방향 시계방향
plt.xticks(angles[:-1], labels, fontsize=13) ## x축 눈금 라벨
ax.tick_params(axis='x', which='major', pad=15) ## x축과 눈금 사이에 여백을 준다.
ax.set_rlabel_position(0) ## y축 각도 설정(degree 단위)
plt.yticks([0, 2, 4, 6, 8, 10], ['0','2','4','6','8','10'], fontsize=10) ## y축 눈금 설정
plt.ylim(0,10)
ax.plot(angles, data, color=color, linewidth=2, linestyle='solid', label=row.Movie) ## 레이더 차트 출력
ax.fill(angles, data, color=color, alpha=0.4) ## 도형 안쪽에 색을 채워준다.
for g in ax.yaxis.get_gridlines(): ## grid line
g.get_path()._interpolation_steps = len(labels)
spine = Spine(axes=ax,
spine_type='circle',
path=Path.unit_regular_polygon(len(labels)))
## Axes의 중심과 반지름을 맞춰준다.
spine.set_transform(Affine2D().scale(.5).translate(.5, .5)+ax.transAxes)
ax.spines = {'polar':spine} ## frame의 모양을 원에서 폴리곤으로 바꿔줘야한다.
plt.legend(loc=(0.9,0.9))
plt.show()
댓글남기기