column 기준
으로 불필요 부분을 제외하기로 하였다. credits.csv
는 확인해보니 우리의 프로젝트에 크게 필요없다고 판단해 사용하지 않았다. import os
os.environ['KAGGLE_USERNAME'] = 'username'
os.environ['KAGGLE_KEY'] = 'key'
import pandas as pd
import numpy as np
!kaggle datasets download -d victorsoeiro/netflix-tv-shows-and-movies
!unzip netflix-tv-shows-and-movies.zip
titles = pd.read_csv('titles.csv')
titles.head(20)
pandas.DataFrame.drop
을 사용하였다. DataFrame.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
참조 문서 : pandas 공식 문서
titles.drop(columns=['id', 'age_certification', 'runtime', 'production_countries',
'seasons', 'imdb_id', 'imdb_score', 'imdb_votes', 'tmdb_popularity'], axis=1)
NaN
타입을 0으로 바꾸려 pandas.Dataframe.fillna(0)
을 시도하자 테이블이 원상태로 돌아가버렸다. title_data = titles[titles['type']=='MOVIE'][['title', 'type', 'description', 'release_year', 'genres', 'tmdb_score']]
title_data.fillna(0, inplace=True)
title_data
ratings
가 있어야 했다. 우리의 데이터셋에는 해당 영화를 찍은 배우 혹은 감독의 정보가 있는 것 같다. 유저 기반 협업 필터링
을 진행해 보았다. 해당 영화에 어떤 유저가 얼마나 평점을 주었는지
확인할 수 있다. 또한 영화의 장르
를 볼 수 있다. import pandas as pd
import numpy as np
ratings = pd.read_csv('ratings.csv')
movies = pd.read_csv('movies.csv')
# ratings와 movies를 movieId를 기준으로 조인한거라 생각하면 됨
movie_ratings = pd.merge(ratings, movies, on='movieId')
movie_ratings.head(20)
title_user
라는 변수에 각 열의 기준을 사용자의 아이디, 컬럼의 기준을 영화 제목으로 잡은 피벗 테이블을 만들어 저장하였다. 또한 NaN 값을 모두 0으로 처리
하였다. title_user = movie_ratings.pivot_table('rating', index='userId', columns='title')
title_user = title_user.fillna(0)
print(title_user)
cosine similarity
를 구하기 전에 의미를 짚고 넘어가보도록 하겠다.cosine similarity
를 구해 보았다. 우리는 1에 유사한 코사인 유사도를 원한다. 엄청 많이.단위 행렬
과 유사하다. 따라서 데칼코마니처럼 1로 이루어진 대각선을 기준으로
양쪽의 값이 똑같다. from sklearn.metrics.pairwise import cosine_similarity
user_based_collab = cosine_similarity(title_user, title_user)
print(user_based_collab)
user_based_collab = pd.DataFrame(user_based_collab, index=title_user.index, columns=title_user.index)
print(user_based_collab)
# 610명 중에서 5번 유저와 가장 유사한 사람은 470번 유저다.
chosen_user = user_based_collab[5].sort_values(ascending=False)[:10]
print(chosen_user)
chosen_user
는 위에 나온 5번 유저와 유사도 값이 가장 비슷한 470번 유저다. chosen_user
이고 열들은 영화 제목이 나오게 된다. title_user
는 모든 유저의 평점이 다 나왔는데 여기서는 딱 470번 유저의 값만 나오게 되는 것이다. chosen_user = user_based_collab[5].sort_values(ascending=False)[:10].index[1]
result = title_user.query(f'userId == {chosen_user}').sort_values(ascending=False, by=chosen_user, axis=1)
print(result)
# 기준 유저인 5번 유저와 유사한 순서를 나타냄(아까 위에서 10명 맨 처음에 뽑은 그 값을 다시 뽑아서 리스트로 만든거임)
user_index_list = user_based_collab[5].sort_values(ascending=False)[:10].index.tolist()
# 이거는 위와 똑같은데 순서가 아닌 가중치를 리스트화한거임
user_weight_list = user_based_collab[5].sort_values(ascending=False)[:10].tolist()
print(user_index_list)
print(user_weight_list)
weighted_sum
이랑 weighted_user
에 아무 값도 들어가지 않아 devision by zero
에러가 났었다. 아 값이 없을수도 있지 참
이라는 생각이 들었다. movie_title = "Batman Forever (1995)"
weighted_sum = []
weighted_user = []
# 0번은 자기 자신이니까 1번부터 10번까지 돌리는거야!
for i in range(1, 10):
value = title_user[movie_title][user_index_list[i]]
print(value)
if int(value) is not 0:
# 5번 유저랑 유사한 사람들이 단 평점에다가 그 사람들의 위에 있는 가중치를 곱한 값
weighted_sum.append(title_user[movie_title][user_index_list[i]] * user_weight_list[i])
# user_weight_list를 다시 한 번 만드는것과 같다.
weighted_user.append(user_weight_list[i])
print(weighted_sum)
print(weighted_user)
print(sum(weighted_sum)/sum(weighted_user))
product
생성$ django-admin startapp product
timeattack_0603/settings.py
에서 생성한 app 등록#### 상단 생략 ####
INSTALLED_APPS = [
'product',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
#### 하단 생략 ####
http://127.0.0.1:8000/
으로 들어가 우주선이 잘 나오나 확인product/models.py
로 이동class
로 만드셨다. 아래 모델을 빠르게 만들고 흐뭇해 했었는데 역시 난 미개했다.ㅋCategory
와 Drink
의 관계이다. Drink
가 Category
의 category를 외래키로 가져다 쓰고 있다. from django.db import models
# Create your models here.
class Category(models.Model):
class Meta:
db_table = 'category'
category = models.CharField(max_length=50)
class Drink(models.Model):
class Meta:
db_table = 'drink'
drink = models.CharField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
# url은 글씨로 저장
# image = models.CharField(max_length=200)
product/admin.py
로 등록하러 가겠다. from django.contrib import admin
from .models import Category, Drink
# Register your models here.
admin.site.register(Category)
admin.site.register(Drink)
url, views, html
을 설정하면 된다. 여기서 순서는 딱히 없으나 나는 timeattack_0603/urls.py
와 product/urls.py
를 먼저 설정하도록 하겠다. timeattack_0603/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('product.urls')),
]
product/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('show/', views.category_view, name="category"),
]
views.category_view
에 눈이 가므로 views.py
를 작성하러 가보겠다. html
의 input의 name
값을 cate에 있는 키값과 같이 정하였고, POST
통신이 이루어질 때 해당 키값이 가지고 있는 value 값을 가지고 바로 Category db에서 아이디 값을 찾기를 원했다. filter
기능을 통해 찾아내었고, 프론트로 보내주었다. from django.shortcuts import render, redirect
from .models import Category, Drink
def category_view(request):
if request.method == 'GET':
return render(request, 'choose.html')
elif request.method == 'POST':
cate = {'cold': '콜드 브루 커피', 'brewed': '브루드 커피', 'espre': '에스프레소'}
if request.POST.get('cold'):
category = Category.objects.get(category=cate['cold']).id
drink = Drink.objects.filter(category_id=category)
elif request.POST.get('brewed'):
category = Category.objects.get(category=cate['brewed']).id
drink = Drink.objects.filter(category_id=category)
else:
category = Category.objects.get(category=cate['espre']).id
drink = Drink.objects.filter(category_id=category)
return render(request, 'drink.html', {'drinks': drink})
template 문법
을 사용해 html들을 연결했다. 보기만 하다가 직접 코딩을 통해 만들어보니 신기하고 추가적으로 딴 것을 안해도 되어 너무 좋다.<!-- choose.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<div>
<input type="checkbox" name="cold"/>
<label for="cold">콜드 브루 커피</label>
</div>
<div>
<input type="checkbox" name="brewed"/>
<label for="brewed">브루드 커피</label>
</div>
<div>
<input type="checkbox" name="espre"/>
<label for="espre">에스프레소</label>
</div>
<button type="submit">선택</button>
</form>
{% block content %}
{% endblock %}
</body>
</html>
<!-- drink.html -->
{% extends 'choose.html' %}
{% block content %}
{% if drinks %}
{% for drink in drinks %}
<p>{{ drink.drink }}</p>
{% endfor %}
{% endif %}
{% endblock %}