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.pyfrom django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('product.urls')),
]
product/urls.pyfrom 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 %}